Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

595
static/js/ketcher2/node_modules/less/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,595 @@
# 2.7.2
2017-01-04
- Revert changes to contrast() function in 2.7.0
# 2.7.1 HOTFIX
2016-05-09
- Revert commit 470af20 (source map performance) which broke source maps
# 2.7.0
2016-05-07
- Fixes for contrast() function
- Allow root functions for plugins
- Allow semi-colon separators in functions
- Performance improvements for source maps
- Fix "blank page" issue in browser
- Compatibility fixes for Node 6.x
- Fix AST to include single-line comments
- Fix reversion for "color-like" words (outputting color values)
# 2.6.1
2016-03-04
- Update Less.js dependencies
- Fix comments after named color regression
- use instanceof operator instead of class comparison optimization
- disallow whitespace in variable calls
# 2.6.0
2016-01-29
- Underscore now allowed in dimension unit
- Fixes for import by reference
- Fix for #2384 Changes HTTPRequest "sync" setting to simply hide the page until less has rendered, browser version is now orders of magnitude faster.
- Added ability to cache stylesheets while using modifyVars
- Error when when image-size functions are used in browser-less
- Fixed extend leaking through nested parent selector. #2586
- Added "or" keyword and allowed arbitrary logical expression in guards
- Fixing #2124 - Parsing Error "Unrecognised input" for color operations
- Logical operator ```and``` now has higher precedence than logical operator ```or```.
- Allow unknown at-rules w/o {} block
# 2.5.3
2015-09-25
- Fix import inline a URL
# 2.5.2
2015-09-24
- No output should result in an empty sourcemap
- Import inline located inside file imported by reference should not be present in output
- Shorthand colors will stay shorthand
- Make percentage work like other math functions and throw an error on NaN
- Fixed mixin definition matching problem when mixin definition contains parameters with default values
- Observe reference for imported comments
# 2.5.1
2015-05-21
- Fix problems with less being async in some browsers
- Minor fix only likely to affect programmatic usage of ruleset find
- Fix error when a namespaced mixin is invoked in global scope
# 2.5.0
2015-04-03
- supports the scoped `@plugin` directive to load function plugins
- All directives are bubbled (e.g. supports), not just media
- Performance improvements to the parser - should help non-chrome browsers with very large less files to be a lot quicker.
- the image size function respects include paths like other file functions
- colour functions take a relative argument that applies percentages relatively instead of absolutely
- include paths now allows : as a separator on windows (recognising and not splitting drive names by the backslash)
- `@import (css)` does not pull the directive above comments
- Fix for import statements without quotes sometimes causing issues
- replace supports dimensions and colours
- the browser field is set in the package.json for use with browserify
- another fix to support paths being passed as a string instead of an array
- detached rulesets can be used as default arguments
- Fix a lot of false warnings about extends
- errors written to stderr more consistently
- consistently keep units if strict units is off
- Better support for comments in function all arguments
# 2.4.0
2015-02-07
- Support for plugins that pre-process (to add libraries silently etc.)
- Empty sourcemaps now work
- Extract and Length functions now ignore comments in a list (more work to come to fix the general problem)
- fragment urls are treated absolute since they refer to the html document
- Extends on a selector joined with `&` now work better
- Nested mixins work better with !important (regression in 2.3.0)
- The promise dependency is now actually optional (introduced in 2.0.0)
- Files with just `\r` newlines now process ok (regression in 2.0.0)
- When strict units is off and the unit is 1/x, (e.g. 1 / 12px) the unit output is x, previously nothing (regression in 2.0.0)
# 2.3.1
2015-01-28
- Fix depends option (regression in 2.3.0)
- Support parent selector (`&`) used in sub element expression (e.g. `:not(.c_&)`)
# 2.3.0
2015-01-27
- add `isruleset` function
- add optional import option, causing less to not fail if file not found
- Fix browsers-side cache.
- Many fixes to import reference - support `@support` and keyframe
- Selectors now interpolate pseudo selectors (e.g. `:@{hover}`)
- Fix comments missed off if they were at the end of the file
- Fix !important used with parametric mixins
- Emits warnings for extends when the target is not found
- include-path now works on data-uri
- variables and function calls work for path in data-uri
- Fix absolute paths not working on imports sometimes.
- Unicode BOM removed again
- Misc. bug fixes
# 2.2.0
2015-01-04
- do not apply relative paths to svg-gradient and data-uri functions data-uri output
- using import filename interpolation and import inline together now works
- deprecate the compression option (still works, but outputs a warning unless silent)
- The node version of less now has image-size, image-width, image-height which return the image dimensions of a file
- Fixed an issue that could cause the parse to occur more than once and the callback be called multiple times
- if you are outputting to the console, lessc defaults to silent so warnings do not end up in output
- `isunit` function supports `''` to test if a dimension has no unit
- data-uri function now counts characters after base64 encoding instead of bytes before encoding to determine ie8 support
- fix bug effecting guards on pseudo class selectors
- do not cache on the browser when used with modifyVars
- detection if less does not parse last character in file
- detection of whether a file is css now requires `/css`, `.css`, `?css`, `&css` instead of just `css`. You can still tell less the type of file using import options.
- remove extra new line added to sourcemap entry inline file
- support safari extension
- less.parse now exposes a way to get the AST. We do not recommend you use this unless you need to.
# 2.1.2
2014-12-20
- Fix for use with requirejs
- Fixes for data-uri function
# 2.1.1
2014-11-27
- Improved keyword and anonymous usage with the replace function
- Added `getCSSAppendage` to sourcemap builder to avoid duplication in plugins
- Fix problem with plugins when used with the promises version of render
- If the render callback throws an exception it now propagates instead of calling the callback again with an error
# 2.1.0
2014-11-23
- Fixed `isSync` option, it was using sync file operations but promises are guaranteed to call back async. We now support promises as a feature rather than the 1st class way of doing things.
- Browser code is now synchronous again, like in v1, meaning it blocks the site until less is compiled
- Some fixes for variable imports which affected filemanagers when synchronous
- Fixed lessc makefile dependencies option
- output now reports back a imports field with an array of imported files
- relative path test for drive names (so windows only) is now case insensitive
- Fix for IE7 - use getChar instead of indexing array
- variables using !important now output !important, which bubbles up to affect the rule
- livereload cache buster is now treated specially
- upgrade dependencies
# 2.0.0
2014-11-09
- Fixed multiplication in non strict units mode to take the left operand unit, in the case that the unit cannot be resolved
- Some fixes for browser cross-compatibility
- browser tests now pass in IE 8-11 and FF
- added index.js and browser.js in root as shortcuts
- fixed some local variable spellings
- support for `@counter-style` directive
# 2.0.0-b3
2014-11-01
- some refactoring of browser structure to allow use of api vs normal browser bundle
- browser bundle no longer leaks require
- browser can now be scoped with just window
- browser `useFileCache` defaults to `true`, but file cache is now cleared when refreshing or in watch mode
# 2.0.0-b2
2014-10-26
- Imports are now sequenced and so are consistent (previously some complex projects might end up with occasional different orderings)
- Imports with variables are better supported - variables can be specified in sub imports
- Support for rebeccapurple
- Browser can now accept options as attributes on the script tag and the link tags e.g. `<script data-verbose="false" src="less.js"...`
- adding a .less file extension is done in the abstract file manager so it the behaviour can be overridden by certain file managers
- Fixed a bug where unquoted urls beginning `//` e.g. `url(//file/file.less)` would be incorrectly interpreted (bug introduced in b-1)
- lessc plugins can be a function, used as a constructor as well as an object - this to allow the plugin more flexibility to be used programattically
# 2.0.0-b1
2014-10-19
- Public Beta / Release Candidate - Feedback welcome
For a guide to breaking changes see [the v2 upgrade guide](http://lesscss.org/usage/#v2-upgrade-guide)
- no longer including old versions of less in the repo or npm
- not including test less and gradle files in npm
- colours now output in the format they are added, so yellow will output yellow, not its hex counterpart
- better parsing - better comment support and comments in brackets can now contain comments including quotes.
- Removal of dependency on clean-css - install less-plugin-clean-css and use --clean-css to reference plugin
- Environment Support - less is now separate from its node and browser environment implementations and adding support for another javascript environment should be straight forward.
- Plugin Support - it is now straight forward to add AST manipulations (see less-plugin-inline-images), file managers (see less-plugin-npm-import) and post processors (see less-plugin-clean-css and less-plugin-autoprefix).
- We now recommend using less.render and using the parser directly is not in the same way as in v2. It is possible but it would require changes and we do not guarantee it will not be broken in minor version releases.
- In the browser, less.pageLoadFinished will be a promise, resolved when less has finished its initial processing. less.refresh and less.modifyVars also return promises.
- In the browser, as before less is used as options, however this is now copied to less.options if you need to access after less has run
- In the browser, the cache can be overwritten by setting less.cache before less loads. After load less.cache will be the default implementation.
- less.js now uses browserify to generate its browser side component
- default values for the sourcemap options have been re-done and improved to hopefully mean creating sourcemaps is easier
- Many smaller bugfixes and API changes. Please let us know if something you relied on has disappeared or an area should be better documented.
# 1.7.5
2014-09-03
- Allow comments in keyframe (complete comment support coming in 2.0)
- pass options to parser from less.render
- Support /deep/ combinator
- handle fragments in data-uri's
- float @charsets to the top correctly
- updates to some dependencies
- Fix interpolated import in media query
- A few other various small corrections
# 1.7.4
2014-07-27
- Handle uppercase paths in browser
- Show error if an empty selector is used in extend
- Fix property merging in directives
- Fix ordering of charset and import directives
- Fix race condition that caused a rules is undefined error sometimes if you had a complex import strategy
- Better error message for imports missing semi-colons or malformed
- Do not use util.print to avoid deprecate warnings in node 0.11
# 1.7.3
2014-06-22
- Include dist files, missing from 1.7.2
- Do not round the results of color functions, like lightness, hue, luma etc.
- Support cover and contain keywords in background definitions
# 1.7.2
2014-06-19
- Allow paths option to be a string (in 1.7.1 less started throwing an exception instead of incorrectly processing the string as an array of chars)
- Do not round numbers when used with javascript (introduced 1.7.0)
# 1.7.1
2014-06-08
- Fix detection of recursive mixins
- Fix the paths option for later versions of node (0.10+)
- Fix paths joining bug
- Fix a number precision issue on some versions of node
- Fix an IE8 issue with importing css files
- Fix IE11 detection for xhr requests
- Modify var works if the last line of a less file is a comment.
- Better detection of valid hex colour codes
- Some stability fixes to support a low number of available file handles
- Support comparing values with different quote types e.g. "test" now === 'test'
- Give better error messages if accessing a url that returns a non 200 status code
- Fix the e() function when passed empty string
- Several minor bug fixes
# 1.7.0
2014-02-27
- Add support for rulesets in variables and passed to mixins to allow wrapping
- Change luma to follow the w3c spec, luma is available as luminance. Contrast still uses luma so you may see differences if your threshold % is close to the existing calculated luma.
- Upgraded clean css which means the --selectors-merge-mode is now renamed --compatibility
- Add support for using variables with @keyframes, @namespace, @charset
- Support property merging with +_ when spaces are needed and keep + for comma separated
- Imports now always import once consistently - a race condition meant previously certain configurations would lead to a different ordering of files
- Fix support for `.mixin(@args...)` when called with no args (e.g. `.mixin();`)
- Do unit conversions with min and max functions. Don't pass through if not understood, throw an error
- Allow % to be passed on its own to the unit function e.g. `unit(10, %)`
- Fix a bug when comparing a unit value to a non-unit value if the unit-value was the multiple of another unit (e.g. cm, mm, deg etc.)
- Fix mixins with media queries in import reference files not being put into the output (they now output, they used to incorrectly not)
- Fix lint mode - now reports all errors
- Fixed a small scope issue with & {} selector rulesets incorrectly making mixins visible - regression from 1.6.2
- Browser - added log level "debug" at 3 to get less logging, The default has changed so unless you set the value to the default you won't see a difference
- Browser - logLevel takes effect regardless of the environment (production/dev)
- Browser - added postProcessor option, a function called to post-process the css before adding to the page
- Browser - use the right request for file access in IE
# 1.6.3
2014-02-08
- Fix issue with calling toCSS twice not working in some situations (like with bootstrap 2)
# 1.6.2
2014-02-02
- The Rhino release is fixed!
- ability to use uppercase colours
- Fix a nasty bug causing syntax errors when selector interpolation is preceded by a long comment (and some other cases)
- Fix a major bug with the variable scope in guards on selectors (e.g. not mixins)
- Fold in `& when () {` to the current selector rather than duplicating it
- fix another issue with array prototypes
- add a url-args option which adds a value to all urls (for cache busting)
- Round numbers to 8 decimal places - thereby stopping javascript precision errors
- some improvements to the default() function in more complex scenarios
- improved missing '{' and '(' detection
# 1.6.1
2014-01-12
- support ^ and ^^ shadow dom selectors
- fix sourcemap selector (used to report end of the element or selector) and directive position (previously not supported)
- fix parsing empty less files
- error on (currently) ambiguous guards on multiple css selectors
- older environments - protect against typeof regex returning function
- Do not use default keyword
- use innerHTML in tests, not innerText
- protect for-in in case Array and Object prototypes have custom fields
# 1.6.0
2014-01-01
- Properties can be interpolated, e.g. @{prefix}-property: value;
- a default function has been added only valid in mixin definitions to determine if no other mixins have been matched
- Added a plugins option that allows specifying an array of visitors run on the less AST
- Performance improvements that may result in approx 20-40% speed up
- Javascript evaluations returning numbers can now be used in calculations/functions
- fixed issue when adding colours, taking the alpha over 1 and breaking when used in colour functions
- when adding together 2 colours with non zero alpha, the alpha will now be combined rather than added
- the advanced colour functions no longer ignore transparency, they blend that too
- Added --clean-option and cleancssOptions to allow passing in clean css options
- rgba declarations are now always clamped e.g. rgba(-1,258,258, -1) becomes rgba(0, 255, 255, 0)
- Fix possible issue with import reference not bringing in styles (may not be a bugfix, just a code tidy)
- Fix some issues with urls() being prefixed twice and unquoted urls in mixins being processed each time they are called
- Fixed error messages for undefined variables in javascript evaluation
- Fixed line/column numbers from math errors
# 1.5.1
2013-11-17
- Added source-map-URL option
- Fixed a bug which meant the minimised 1.5.0 browser version was not wrapped, meaning it interfered with require js
- Fixed a bug where the browser version assume port was specified
- Added the ability to specify variables on the command line
- Upgraded clean-css and fixed it from trying to import
- correct a bug meaning imports weren't synchronous (syncImport option available for full synchronous behaviour)
- better mixin matching behaviour with calling multiple classes e.g. .a.b.c;
# 1.5.0
2013-10-21
- sourcemap support
- support for import inline option to include css that you do NOT want less to parse e.g. `@import (inline) "file.css";`
- better support for modifyVars (refresh styles with new variables, using a file cache), is now more resiliant
- support for import reference option to reference external css, but not output it. Any mixin calls or extend's will be output.
- support for guards on selectors (currently only if you have a single selector)
- allow property merging through the +: syntax
- Added min/max functions
- Added length function and improved extract to work with comma separated values
- when using import multiple, sub imports are imported multiple times into final output
- fix bad spaces between namespace operators
- do not compress comment if it begins with an exclamation mark
- Fix the saturate function to pass through when using the CSS syntax
- Added svg-gradient function
- Added no-js option to lessc (in browser, use javascriptEnabled: false) which disallows JavaScript in less files
- switched from the little supported and buggy cssmin (previously ycssmin) to clean-css
- support transparent as a color, but not convert between rgba(0, 0, 0, 0) and transparent
- remove sys.puts calls to stop deprecation warnings in future node.js releases
- Browser: added logLevel option to control logging (2 = everything, 1 = errors only, 0 = no logging)
- Browser: added errorReporting option which can be "html" (default) or "console" or a function
- Now uses grunt for building and testing
- A few bug fixes for media queries, extends, scoping, compression and import once.
# 1.4.2
2013-07-20
- if you don't pass a strict maths option, font size/line height options are output correctly again
- npmignore now include .gitattributes
- property names may include capital letters
- various windows path fixes (capital letters, multiple // in a path)
# 1.4.1
2013-07-05
- fix syncImports and yui-compress option, as they were being ignored
- fixed several global variable leaks
- handle getting null or undefined passed as the options object
# 1.4.0
2013-06-05
- fix passing of strict maths option
# 1.4.0 Beta 4
2013-05-04
- change strictMaths to strictMath. Enable this with --strict-math=on in lessc and strictMath:true in JavaScript.
- change lessc option for strict units to --strict-units=off
# 1.4.0 Beta 3
2013-04-30
- strictUnits now defaults to false and the true case now gives more useful but less correct results, e.g. 2px/1px = 2px
- Process ./ when having relative paths
- add isunit function for mixin guards and non basic units
- extends recognise attributes
- exception errors extend the JavaScript Error
- remove es-5-shim as standard from the browser
- Fix path issues with windows/linux local paths
# 1.4.0 Beta 1 & 2
2013-03-07
- support for `:extend()` in selectors (e.g. `input:extend(.button) {}`) and `&:extend();` in ruleset (e.g. `input { &:extend(.button all); }`)
- maths is now only done inside brackets. This means font: statements, media queries and the calc function can use a simpler format without being escaped. Disable this with --strict-maths-off in lessc and strictMaths:false in JavaScript.
- units are calculated, e.g. 200cm+1m = 3m, 3px/1px = 3. If you use units inconsistently you will get an error. Suppress this error with --strict-units-off in lessc or strictUnits:false in JavaScript
- `(~"@var")` selector interpolation is removed. Use @{var} in selectors to have variable selectors
- default behaviour of import is to import each file once. `@import-once` has been removed.
- You can specify options on imports to force it to behave as css or less `@import (less) "file.css"` will process the file as less
- variables in mixins no longer 'leak' into their calling scope
- added data-uri function which will inline an image into the output css. If ieCompat option is true and file is too large, it will fallback to a url()
- significant bug fixes to our debug options
- other parameters can be used as defaults in mixins e.g. .a(@a, @b:@a)
- an error is shown if properties are used outside of a ruleset
- added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 14
- added luma, hsvhue, hsvsaturation, hsvvalue functions
- added pow, pi, mod, tan, sin, cos, atan, asin, acos and sqrt math functions
- added convert function, e.g. convert(1rad, deg) => value in degrees
- lessc makes output directories if they don't exist
- lessc `@import` supports https and 301's
- lessc "-depends" option for lessc writes out the list of import files used in makefile format
- lessc "-lint" option just reports errors
- support for namespaces in attributes and selector interpolation in attributes
- other bug fixes
# 1.3.3
2012-12-30
- Fix critical bug with mixin call if using multiple brackets
- when using the filter contrast function, the function is passed through if the first argument is not a color
# 1.3.2
2012-12-28
- browser and server url re-writing is now aligned to not re-write (previous lessc behaviour)
- url-rewriting can be made to re-write to be relative to the entry file using the relative-urls option (less.relativeUrls option)
- rootpath option can be used to add a base path to every url
- Support mixin argument separator of ';' so you can pass comma separated values. e.g. `.mixin(23px, 12px;);`
- Fix lots of problems with named arguments in corner cases, not behaving as expected
- hsv, hsva, unit functions
- fixed lots more bad error messages
- fix `@import-once` to use the full path, not the relative one for determining if an import has been imported already
- support `:not(:nth-child(3))`
- mixin guards take units into account
- support unicode descriptors (`U+00A1-00A9`)
- support calling mixins with a stack when using `&` (broken in 1.3.1)
- support `@namespace` and namespace combinators
- when using % with colour functions, take into account a colour is out of 256
- when doing maths with a % do not divide by 100 and keep the unit
- allow url to contain % (e.g. %20 for a space)
- if a mixin guard stops execution a default mixin is not required
- units are output in strings (use the unit function if you need to get the value without unit)
- do not infinite recurse when mixins call mixins of the same name
- fix issue on important on mixin calls
- fix issue with multiple comments being confused
- tolerate multiple semi-colons on rules
- ignore subsequant `@charset`
- syncImport option for node.js to read files syncronously
- write the output directory if it is missing
- change dependency on cssmin to ycssmin
- lessc can load files over http
- allow calling less.watch() in non dev mode
- don't cache in dev mode
- less files cope with query parameters better
- sass debug statements are now chrome compatible
- modifyVars function added to re-render with different root variables
# 1.3.1
2012-10-18
- Support for comment and @media debugging statements
- bug fix for async access in chrome extensions
- new functions tint, shade, multiply, screen, overlay, hardlight, difference, exclusion, average, negation, softlight, red, green, blue, contrast
- allow escaped characters in attributes
- in selectors support @{a} directly, e.g. .a.@{a} { color: black; }
- add fraction parameter to round function
- much better support for & selector
- preserve order of link statements client side
- lessc has better help
- rhino version fixed
- fix bugs in clientside error handling
- support dpi, vmin, vm, dppx, dpcm units
- Fix ratios in media statements
- in mixin guards allow comparing colors and strings
- support for -*-keyframes (for -khtml but now supports any)
- in mix function, default weight to 50%
- support @import-once
- remove duplicate rules in output
- implement named parameters when calling mixins
- many numerous bug fixes
# 1.3.0
2012-03-10
- @media bubbling
- Support arbitrary entities as selectors
- [Variadic argument support](https://gist.github.com/1933613)
- Behaviour of zero-arity mixins has [changed](https://gist.github.com/1933613)
- Allow `@import` directives in any selector
- Media-query features can now be a variable
- Automatic merging of media-query conditions
- Fix global variable leaks
- Fix error message on wrong-arity call
- Fix an `@arguments` behaviour bug
- Fix `::` selector output
- Fix a bug when using @media with mixins
# 1.2.1
2012-01-15
- Fix imports in browser
- Improve error reporting in browser
- Fix Runtime error reports from imported files
- Fix `File not found` import error reporting
# 1.2.0
2012-01-07
- Mixin guards
- New function `percentage`
- New `color` function to parse hex color strings
- New type-checking stylesheet functions
- Fix Rhino support
- Fix bug in string arguments to mixin call
- Fix error reporting when index is 0
- Fix browser support in WebKit and IE
- Fix string interpolation bug when var is empty
- Support `!important` after mixin calls
- Support vanilla @keyframes directive
- Support variables in certain css selectors, like `nth-child`
- Support @media and @import features properly
- Improve @import support with media features
- Improve error reports from imported files
- Improve function call error reporting
- Improve error-reporting

50
static/js/ketcher2/node_modules/less/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,50 @@
# Contributing to Less.js
> We welcome feature requests and bug reports. Please read these guidelines before submitting one.
<span class="warning">**Words that begin with the at sign (`@`) must be wrapped in backticks!** </span>. As a courtesy to avoid sending notifications to any user that might have the `@username` being referenced, please remember that GitHub usernames also start with the at sign. If you don't wrap them in backticks, users will get unintended notifications from you.
GitHub has other great markdown features as well, [go here to learn more about them](https://help.github.com/articles/github-flavored-markdown).
## Reporting Issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems that we can fix within the Less.js core. Please read the following guidelines before opening any issue.
1. **Search for existing issues.** We get a lot of duplicate issues, and you'd help us out a lot by first checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a fix available.
2. **Create an isolated and reproducible test case.** Be sure the problem exists in Less.js's code with [reduced test cases](http://css-tricks.com/reduced-test-cases/) that should be included in each bug report.
3. **Test with the latest version**. We get a lot of issues that could be resolved by updating your version of Less.js.
3. **Include an example with source.** E.g. You can use [less2css.org](http://less2css.org/) to create a short test case.
4. **Share as much information as possible.** Include operating system and version. Describe how you use Less. If you use it in the browser, please include browser and version, and the version of Less.js you're using. Let us know if you're using the command line (`lessc`) or an external tool. And try to include steps to reproduce the bug.
5. If you have a solution or suggestion for how to fix the bug you're reporting, please include it, or make a pull request - don't assume the maintainers know how to fix it just because you do.
Please report documentation issues in [the documentation project](https://github.com/less/less-docs).
## Feature Requests
* Please search for existing feature requests first to see if something similar already exists.
* Include a clear and specific use-case. We love new ideas, but we do not add language features without a reason.
* Consider whether or not your language feature would be better as a function or implemented in a 3rd-party build system such as [assemble-less](http://github.com/assemble/assemble-less).
## Pull Requests
_Pull requests are encouraged!_
* Start by adding a feature request to get feedback and see how your idea is received.
* If your pull request solves an existing issue, but it's different in some way, _please create a new issue_ and make sure to discuss it with the core contributors. Otherwise you risk your hard work being rejected.
* Do not change the **./dist/** folder, we do this when releasing
* _Please add tests_ for your work. Tests are invoked using `grunt test` command. It will run both node.js tests and browser ([PhantomJS](http://phantomjs.org/)) tests.
### Coding Standards
* Always use spaces, never tabs
* End lines in semi-colons.
* Loosely aim towards jsHint standards
## Developing
If you want to take an issue just add a small comment saying you are having a go at something, so we don't get duplication.
Learn more about [developing Less.js](http://lesscss.org/usage/#developing-less).

458
static/js/ketcher2/node_modules/less/Gruntfile.js generated vendored Normal file
View File

@ -0,0 +1,458 @@
'use strict';
module.exports = function (grunt) {
// Report the elapsed execution time of tasks.
require('time-grunt')(grunt);
var COMPRESS_FOR_TESTS = true;
// Project configuration.
grunt.initConfig({
// Metadata required for build.
build: grunt.file.readYAML('build/build.yml'),
pkg: grunt.file.readJSON('package.json'),
meta: {
copyright: 'Copyright (c) 2009-<%= grunt.template.today("yyyy") %>',
banner: '/*!\n' +
' * Less - <%= pkg.description %> v<%= pkg.version %>\n' +
' * http://lesscss.org\n' +
' *\n' +
' * <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>>\n' +
' * Licensed under the <%= pkg.license %> License.\n' +
' *\n' +
' */\n\n' +
' /**' +
' * @license <%= pkg.license %>\n' +
' */\n\n'
},
shell: {
options: {stdout: true, failOnError: true},
test: {
command: 'node test'
},
benchmark: {
command: 'node benchmark/index.js'
},
"sourcemap-test": {
command: [
'node bin/lessc --source-map=test/sourcemaps/maps/import-map.map test/less/import.less test/sourcemaps/import.css',
'node bin/lessc --source-map test/less/sourcemaps/basic.less test/sourcemaps/basic.css'
].join('&&')
}
},
browserify: {
browser: {
src: ['./lib/less-browser/bootstrap.js'],
options: {
exclude: ["promise"],
browserifyOptions: {
standalone: 'less'
}
},
dest: 'tmp/less.js'
}
},
concat: {
options: {
stripBanners: 'all',
banner: '<%= meta.banner %>'
},
browsertest: {
src: COMPRESS_FOR_TESTS ? '<%= uglify.test.dest %>' : '<%= browserify.browser.dest %>',
dest: 'test/browser/less.js'
},
dist: {
src: '<%= browserify.browser.dest %>',
dest: 'dist/less.js'
},
// Rhino
rhino: {
options: {
banner: '/* Less.js v<%= pkg.version %> RHINO | <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> */\n\n',
footer: '' // override task-level footer
},
src: ['<%= build.rhino %>'],
dest: 'dist/less-rhino.js'
},
// lessc for Rhino
rhinolessc: {
options: {
banner: '/* Less.js v<%= pkg.version %> RHINO | <%= meta.copyright %>, <%= pkg.author.name %> <<%= pkg.author.email %>> */\n\n',
footer: '' // override task-level footer
},
src: ['<%= build.rhinolessc %>'],
dest: 'dist/lessc-rhino.js'
}
},
uglify: {
options: {
banner: '<%= meta.banner %>',
mangle: true,
compress: {
pure_getters: true
}
},
dist: {
src: ['<%= concat.dist.dest %>'],
dest: 'dist/less.min.js'
},
test: {
src: '<%= browserify.browser.dest %>',
dest: 'tmp/less.min.js'
}
},
jshint: {
options: {jshintrc: '.jshintrc'},
files: {
src: [
'Gruntfile.js',
'lib/less/**/*.js',
'lib/less-node/**/*.js',
'lib/less-browser/**/*.js',
'lib/less-rhino/**/*.js',
'bin/lessc'
]
}
},
jscs: {
src: ["test/**/*.js", "lib/less*/**/*.js", "bin/lessc"],
options: {
config: ".jscsrc"
}
},
connect: {
server: {
options: {
port: 8081
}
}
},
jasmine: {
options: {
keepRunner: true,
host: 'http://localhost:8081/',
vendor: ['test/browser/jasmine-jsreporter.js', 'test/browser/common.js', 'test/browser/less.js'],
template: 'test/browser/test-runner-template.tmpl'
},
main: {
// src is used to build list of less files to compile
src: ['test/less/*.less', '!test/less/javascript.less', '!test/less/urls.less', '!test/less/empty.less'],
options: {
helpers: 'test/browser/runner-main-options.js',
specs: 'test/browser/runner-main-spec.js',
outfile: 'tmp/browser/test-runner-main.html'
}
},
legacy: {
src: ['test/less/legacy/*.less'],
options: {
helpers: 'test/browser/runner-legacy-options.js',
specs: 'test/browser/runner-legacy-spec.js',
outfile: 'tmp/browser/test-runner-legacy.html'
}
},
strictUnits: {
src: ['test/less/strict-units/*.less'],
options: {
helpers: 'test/browser/runner-strict-units-options.js',
specs: 'test/browser/runner-strict-units-spec.js',
outfile: 'tmp/browser/test-runner-strict-units.html'
}
},
errors: {
src: ['test/less/errors/*.less', '!test/less/errors/javascript-error.less', 'test/browser/less/errors/*.less'],
options: {
timeout: 20000,
helpers: 'test/browser/runner-errors-options.js',
specs: 'test/browser/runner-errors-spec.js',
outfile: 'tmp/browser/test-runner-errors.html'
}
},
noJsErrors: {
src: ['test/less/no-js-errors/*.less'],
options: {
helpers: 'test/browser/runner-no-js-errors-options.js',
specs: 'test/browser/runner-no-js-errors-spec.js',
outfile: 'tmp/browser/test-runner-no-js-errors.html'
}
},
browser: {
src: ['test/browser/less/*.less'],
options: {
helpers: 'test/browser/runner-browser-options.js',
specs: 'test/browser/runner-browser-spec.js',
outfile: 'tmp/browser/test-runner-browser.html'
}
},
relativeUrls: {
src: ['test/browser/less/relative-urls/*.less'],
options: {
helpers: 'test/browser/runner-relative-urls-options.js',
specs: 'test/browser/runner-relative-urls-spec.js',
outfile: 'tmp/browser/test-runner-relative-urls.html'
}
},
rootpath: {
src: ['test/browser/less/rootpath/*.less'],
options: {
helpers: 'test/browser/runner-rootpath-options.js',
specs: 'test/browser/runner-rootpath-spec.js',
outfile: 'tmp/browser/test-runner-rootpath.html'
}
},
rootpathRelative: {
src: ['test/browser/less/rootpath-relative/*.less'],
options: {
helpers: 'test/browser/runner-rootpath-relative-options.js',
specs: 'test/browser/runner-rootpath-relative-spec.js',
outfile: 'tmp/browser/test-runner-rootpath-relative.html'
}
},
production: {
src: ['test/browser/less/production/*.less'],
options: {
helpers: 'test/browser/runner-production-options.js',
specs: 'test/browser/runner-production-spec.js',
outfile: 'tmp/browser/test-runner-production.html'
}
},
modifyVars: {
src: ['test/browser/less/modify-vars/*.less'],
options: {
helpers: 'test/browser/runner-modify-vars-options.js',
specs: 'test/browser/runner-modify-vars-spec.js',
outfile: 'tmp/browser/test-runner-modify-vars.html'
}
},
globalVars: {
src: ['test/browser/less/global-vars/*.less'],
options: {
helpers: 'test/browser/runner-global-vars-options.js',
specs: 'test/browser/runner-global-vars-spec.js',
outfile: 'tmp/browser/test-runner-global-vars.html'
}
},
postProcessor: {
src: ['test/browser/less/postProcessor/*.less'],
options: {
helpers: 'test/browser/runner-postProcessor-options.js',
specs: 'test/browser/runner-postProcessor.js',
outfile: 'tmp/browser/test-runner-post-processor.html'
}
},
postProcessorPlugin: {
src: ['test/less/postProcessorPlugin/*.less'],
options: {
helpers: ['test/plugins/postprocess/index.js','test/browser/runner-postProcessorPlugin-options.js'],
specs: 'test/browser/runner-postProcessorPlugin.js',
outfile: 'tmp/browser/test-runner-post-processor-plugin.html'
}
},
preProcessorPlugin: {
src: ['test/less/preProcessorPlugin/*.less'],
options: {
helpers: ['test/plugins/preprocess/index.js','test/browser/runner-preProcessorPlugin-options.js'],
specs: 'test/browser/runner-preProcessorPlugin.js',
outfile: 'tmp/browser/test-runner-pre-processor-plugin.html'
}
},
visitorPlugin: {
src: ['test/less/visitorPlugin/*.less'],
options: {
helpers: ['test/plugins/visitor/index.js','test/browser/runner-VisitorPlugin-options.js'],
specs: 'test/browser/runner-VisitorPlugin.js',
outfile: 'tmp/browser/test-runner-visitor-plugin.html'
}
},
filemanagerPlugin: {
src: ['test/less/filemanagerPlugin/*.less'],
options: {
helpers: ['test/plugins/filemanager/index.js','test/browser/runner-filemanagerPlugin-options.js'],
specs: 'test/browser/runner-filemanagerPlugin.js',
outfile: 'tmp/browser/test-runner-filemanager-plugin.html'
}
}
},
'saucelabs-jasmine': {
all: {
options: {
urls: ["filemanager-plugin","visitor-plugin","pre-processor-plugin","post-processor-plugin","post-processor", "global-vars", "modify-vars", "production", "rootpath-relative",
"rootpath", "relative-urls", "browser", "no-js-errors", "legacy", "strict-units"
].map(function(testName) {
return "http://localhost:8081/tmp/browser/test-runner-" + testName + ".html";
}),
testname: 'Sauce Unit Test for less.js',
browsers: [{
browserName: "chrome",
version: '',
platform: 'Windows 8'
},
{
browserName: "firefox",
version: '33',
platform: 'Linux'
},
{
browserName: "iPad",
version: '8.0',
platform: 'OS X 10.9',
'device-orientation': 'portrait'
},
{
browserName: "internet explorer",
version: '8',
platform: 'Windows XP'
},
{
browserName: "internet explorer",
version: '9',
platform: 'Windows 7'
},
{
browserName: "internet explorer",
version: '10',
platform: 'Windows 7'
},
{
browserName: "internet explorer",
version: '11',
platform: 'Windows 8.1'
}],
sauceConfig: {
'record-video': process.env.TRAVIS_BRANCH !== "master",
'record-screenshots': process.env.TRAVIS_BRANCH !== "master",
'idle-timeout': 100, 'max-duration': 120,
build: process.env.TRAVIS_BRANCH === "master" ? process.env.TRAVIS_JOB_ID : undefined,
tags: [process.env.TRAVIS_BUILD_NUMBER, process.env.TRAVIS_PULL_REQUEST, process.env.TRAVIS_BRANCH]
},
throttled: 3
}
}
},
// Clean the version of less built for the tests
clean: {
test: ['test/browser/less.js', 'tmp', 'test/less-bom'],
"sourcemap-test": ['test/sourcemaps/*.css', 'test/sourcemaps/*.map'],
sauce_log: ["sc_*.log"]
}
});
// Load these plugins to provide the necessary tasks
require('jit-grunt')(grunt);
// Actually load this plugin's task(s).
grunt.loadTasks('build/tasks');
// by default, run tests
grunt.registerTask('default', [
'test'
]);
// Release
grunt.registerTask('dist', [
'browserify:browser',
'concat:dist',
'uglify:dist'
]);
// Release Rhino Version
grunt.registerTask('rhino', [
'browserify:rhino',
'concat:rhino',
'concat:rhinolessc'
]);
// Create the browser version of less.js
grunt.registerTask('browsertest-lessjs', [
'browserify:browser',
'uglify:test',
'concat:browsertest'
]);
// Run all browser tests
grunt.registerTask('browsertest', [
'browsertest-lessjs',
'connect',
'jasmine'
]);
// setup a web server to run the browser tests in a browser rather than phantom
grunt.registerTask('browsertest-server', [
'browsertest-lessjs',
'jasmine::build',
'connect::keepalive'
]);
var previous_force_state = grunt.option("force");
grunt.registerTask("force",function(set) {
if (set === "on") {
grunt.option("force",true);
}
else if (set === "off") {
grunt.option("force",false);
}
else if (set === "restore") {
grunt.option("force",previous_force_state);
}
});
grunt.registerTask('sauce', [
'browsertest-lessjs',
'jasmine::build',
'connect',
'sauce-after-setup'
]);
// setup a web server to run the browser tests in a browser rather than phantom
grunt.registerTask('sauce-after-setup', [
'saucelabs-jasmine',
'clean:sauce_log'
]);
var testTasks = [
'clean',
'jshint',
'jscs',
'shell:test',
'browsertest'
];
if (isNaN(Number(process.env.TRAVIS_PULL_REQUEST, 10)) &&
Number(process.env.TRAVIS_NODE_VERSION) === 0.11 &&
(process.env.TRAVIS_BRANCH === "master" || process.env.TRAVIS_BRANCH === "sauce")) {
testTasks.push("force:on");
testTasks.push("sauce-after-setup");
testTasks.push("force:off");
}
// Run all tests
grunt.registerTask('test', testTasks);
// Run all tests
grunt.registerTask('quicktest', testTasks.slice(0, testTasks.length -1));
// generate a good test environment for testing sourcemaps
grunt.registerTask('sourcemap-test', [
'clean:sourcemap-test',
'shell:sourcemap-test',
'connect::keepalive'
]);
// Run benchmark
grunt.registerTask('benchmark', [
'shell:benchmark'
]);
};

177
static/js/ketcher2/node_modules/less/LICENSE generated vendored Normal file
View File

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

56
static/js/ketcher2/node_modules/less/README.md generated vendored Normal file
View File

@ -0,0 +1,56 @@
[![npm version](https://badge.fury.io/js/less.svg)](http://badge.fury.io/js/less) [![Build Status](https://travis-ci.org/less/less.js.svg?branch=master)](https://travis-ci.org/less/less.js)
[![Dependencies](https://david-dm.org/less/less.js.svg)](https://david-dm.org/less/less.js) [![devDependency Status](https://david-dm.org/less/less.js/dev-status.svg)](https://david-dm.org/less/less.js#info=devDependencies) [![optionalDependency Status](https://david-dm.org/less/less.js/optional-status.svg)](https://david-dm.org/less/less.js#info=optionalDependencies)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/less.svg)](https://saucelabs.com/u/less) [![Build status](https://ci.appveyor.com/api/projects/status/bx2qspy3qbuxpl9q/branch/master?svg=true)](https://ci.appveyor.com/project/lukeapage/less-js/branch/master)
# [Less.js](http://lesscss.org)
> The **dynamic** stylesheet language. [http://lesscss.org](http://lesscss.org).
This is the JavaScript, official, stable version of Less.
###### :point_right: [![Join the chat at https://gitter.im/less/less.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/less/less.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <sup>Chat with Less.js users</sup>
## Getting Started
Options for adding Less.js to your project:
* Install with [npm](https://npmjs.org): `npm install less`
* [Download the latest release][download]
* Clone the repo: `git clone https://github.com/less/less.js.git`
## More information
For general information on the language, configuration options or usage visit [lesscss.org](http://lesscss.org).
Here are other resources for using Less.js:
* [stackoverflow.com][so] is a great place to get answers about Less.
* [Less.js Issues][issues] for reporting bugs
## Contributing
Please read [CONTRIBUTING.md](CONTRIBUTING.md). Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com).
### Reporting Issues
Before opening any issue, please search for existing issues and read the [Issue Guidelines](https://github.com/necolas/issue-guidelines), written by [Nicolas Gallagher](https://github.com/necolas). After that if you find a bug or would like to make feature request, [please open a new issue][issues].
Please report documentation issues in [the documentation project](https://github.com/less/less-docs).
### Development
Read [Developing Less](http://lesscss.org/usage/#developing-less).
## Release History
See the [changelog](CHANGELOG.md)
## [License](LICENSE)
Copyright (c) 2009-2016 [Alexis Sellier](http://cloudhead.io) & The Core Less Team
Licensed under the [Apache License](LICENSE).
[so]: http://stackoverflow.com/questions/tagged/less "StackOverflow.com"
[issues]: https://github.com/less/less.js/issues "GitHub Issues for Less.js"
[download]: https://github.com/less/less.js/zipball/master "Download Less.js"

33
static/js/ketcher2/node_modules/less/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,33 @@
# Test against these versions of Node.js.
environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4"
- nodejs_version: "6"
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node 0.STABLE.latest
- ps: Install-Product node $env:nodejs_version
# Use npm v2
- npm -g install npm@2
- set PATH=%APPDATA%\npm;%PATH%
- npm -v
# Typical npm stuff.
- npm install
# Grunt-specific stuff.
- npm install -g grunt-cli
# Post-install test scripts.
test_script:
# Output useful info for debugging.
- node --version && npm --version
# Run test
- grunt test
# Don't actually build.
build: off
# Set build version format here instead of in the admin panel.
version: "{build}"

512
static/js/ketcher2/node_modules/less/bin/lessc generated vendored Executable file
View File

@ -0,0 +1,512 @@
#!/usr/bin/env node
var path = require('path'),
fs = require('../lib/less-node/fs'),
os = require("os"),
errno,
mkdirp;
try {
errno = require('errno');
} catch (err) {
errno = null;
}
var less = require('../lib/less-node'),
pluginLoader = new less.PluginLoader(less),
plugin,
plugins = [];
var args = process.argv.slice(1);
var silent = false,
verbose = false,
options = {
depends: false,
compress: false,
max_line_len: -1,
lint: false,
paths: [],
color: true,
strictImports: false,
insecure: false,
rootpath: '',
relativeUrls: false,
ieCompat: true,
strictMath: false,
strictUnits: false,
globalVars: null,
modifyVars: null,
urlArgs: '',
plugins: plugins
};
var sourceMapOptions = {};
var continueProcessing = true;
// Calling process.exit does not flush stdout always. Instead of exiting the process, we set the process' exitCode,
// close all handles and wait for the event loop to exit the process.
// @see https://github.com/nodejs/node/issues/6409
// Unfortunately, node 0.10.x does not support setting process.exitCode, so we need to call reallyExit() explicitly.
// @see https://nodejs.org/api/process.html#process_process_exitcode
// Additionally we also need to make sure that uncaughtExceptions are never swallowed.
// @see https://github.com/less/less.js/issues/2881
// This code can safely be removed if node 0.10.x is not supported anymore.
process.on("exit", function() { process.reallyExit(process.exitCode); });
process.on("uncaughtException", function(err) {
console.error(err);
process.exitCode = 1;
});
// This code will still be required because otherwise rejected promises would not be reported to the user
process.on("unhandledRejection", function(err) {
console.error(err);
process.exitCode = 1;
});
var checkArgFunc = function(arg, option) {
if (!option) {
console.error(arg + " option requires a parameter");
continueProcessing = false;
process.exitCode = 1;
return false;
}
return true;
};
var checkBooleanArg = function(arg) {
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
if (!onOff) {
console.error(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
continueProcessing = false;
process.exitCode = 1;
return false;
}
return Boolean(onOff[2]);
};
var parseVariableOption = function(option, variables) {
var parts = option.split('=', 2);
variables[parts[0]] = parts[1];
};
var sourceMapFileInline = false;
function printUsage() {
less.lesscHelper.printUsage();
pluginLoader.printUsage(plugins);
continueProcessing = false;
}
// self executing function so we can return
(function() {
args = args.filter(function (arg) {
var match;
match = arg.match(/^-I(.+)$/);
if (match) {
options.paths.push(match[1]);
return false;
}
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
if (match) {
arg = match[1];
} else {
return arg;
}
switch (arg) {
case 'v':
case 'version':
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
continueProcessing = false;
break;
case 'verbose':
verbose = true;
break;
case 's':
case 'silent':
silent = true;
break;
case 'l':
case 'lint':
options.lint = true;
break;
case 'strict-imports':
options.strictImports = true;
break;
case 'h':
case 'help':
printUsage();
break;
case 'x':
case 'compress':
options.compress = true;
break;
case 'insecure':
options.insecure = true;
break;
case 'M':
case 'depends':
options.depends = true;
break;
case 'max-line-len':
if (checkArgFunc(arg, match[2])) {
options.maxLineLen = parseInt(match[2], 10);
if (options.maxLineLen <= 0) {
options.maxLineLen = -1;
}
}
break;
case 'no-color':
options.color = false;
break;
case 'no-ie-compat':
options.ieCompat = false;
break;
case 'no-js':
options.javascriptEnabled = false;
break;
case 'include-path':
if (checkArgFunc(arg, match[2])) {
// ; supported on windows.
// : supported on windows and linux, excluding a drive letter like C:\ so C:\file:D:\file parses to 2
options.paths = match[2]
.split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':')
.map(function(p) {
if (p) {
return path.resolve(process.cwd(), p);
}
});
}
break;
case 'line-numbers':
if (checkArgFunc(arg, match[2])) {
options.dumpLineNumbers = match[2];
}
break;
case 'source-map':
options.sourceMap = true;
if (match[2]) {
sourceMapOptions.sourceMapFullFilename = match[2];
}
break;
case 'source-map-rootpath':
if (checkArgFunc(arg, match[2])) {
sourceMapOptions.sourceMapRootpath = match[2];
}
break;
case 'source-map-basepath':
if (checkArgFunc(arg, match[2])) {
sourceMapOptions.sourceMapBasepath = match[2];
}
break;
case 'source-map-map-inline':
sourceMapFileInline = true;
options.sourceMap = true;
break;
case 'source-map-less-inline':
sourceMapOptions.outputSourceFiles = true;
break;
case 'source-map-url':
if (checkArgFunc(arg, match[2])) {
sourceMapOptions.sourceMapURL = match[2];
}
break;
case 'rp':
case 'rootpath':
if (checkArgFunc(arg, match[2])) {
options.rootpath = match[2].replace(/\\/g, '/');
}
break;
case "ru":
case "relative-urls":
options.relativeUrls = true;
break;
case "sm":
case "strict-math":
if (checkArgFunc(arg, match[2])) {
options.strictMath = checkBooleanArg(match[2]);
}
break;
case "su":
case "strict-units":
if (checkArgFunc(arg, match[2])) {
options.strictUnits = checkBooleanArg(match[2]);
}
break;
case "global-var":
if (checkArgFunc(arg, match[2])) {
if (!options.globalVars) {
options.globalVars = {};
}
parseVariableOption(match[2], options.globalVars);
}
break;
case "modify-var":
if (checkArgFunc(arg, match[2])) {
if (!options.modifyVars) {
options.modifyVars = {};
}
parseVariableOption(match[2], options.modifyVars);
}
break;
case 'url-args':
if (checkArgFunc(arg, match[2])) {
options.urlArgs = match[2];
}
break;
case 'plugin':
var splitupArg = match[2].match(/^([^=]+)(=(.*))?/),
name = splitupArg[1],
pluginOptions = splitupArg[3];
plugin = pluginLoader.tryLoadPlugin(name, pluginOptions);
if (plugin) {
plugins.push(plugin);
} else {
console.error("Unable to load plugin " + name +
" please make sure that it is installed under or at the same level as less");
process.exitCode = 1;
}
break;
default:
plugin = pluginLoader.tryLoadPlugin("less-plugin-" + arg, match[2]);
if (plugin) {
plugins.push(plugin);
} else {
console.error("Unable to interpret argument " + arg +
" - if it is a plugin (less-plugin-" + arg + "), make sure that it is installed under or at" +
" the same level as less");
process.exitCode = 1;
}
break;
}
});
if (!continueProcessing) {
return;
}
var input = args[1];
if (input && input != '-') {
input = path.resolve(process.cwd(), input);
}
var output = args[2];
var outputbase = args[2];
if (output) {
output = path.resolve(process.cwd(), output);
}
if (options.sourceMap) {
sourceMapOptions.sourceMapInputFilename = input;
if (!sourceMapOptions.sourceMapFullFilename) {
if (!output && !sourceMapFileInline) {
console.error("the sourcemap option only has an optional filename if the css filename is given");
console.error("consider adding --source-map-map-inline which embeds the sourcemap into the css");
process.exitCode = 1;
return;
}
// its in the same directory, so always just the basename
if (output) {
sourceMapOptions.sourceMapOutputFilename = path.basename(output);
sourceMapOptions.sourceMapFullFilename = output + ".map";
}
// its in the same directory, so always just the basename
if ('sourceMapFullFilename' in sourceMapOptions) {
sourceMapOptions.sourceMapFilename = path.basename(sourceMapOptions.sourceMapFullFilename);
}
} else if (options.sourceMap && !sourceMapFileInline) {
var mapFilename = path.resolve(process.cwd(), sourceMapOptions.sourceMapFullFilename),
mapDir = path.dirname(mapFilename),
outputDir = path.dirname(output);
// find the path from the map to the output file
sourceMapOptions.sourceMapOutputFilename = path.join(
path.relative(mapDir, outputDir), path.basename(output));
// make the sourcemap filename point to the sourcemap relative to the css file output directory
sourceMapOptions.sourceMapFilename = path.join(
path.relative(outputDir, mapDir), path.basename(sourceMapOptions.sourceMapFullFilename));
}
}
if (sourceMapOptions.sourceMapBasepath === undefined) {
sourceMapOptions.sourceMapBasepath = input ? path.dirname(input) : process.cwd();
}
if (sourceMapOptions.sourceMapRootpath === undefined) {
var pathToMap = path.dirname((sourceMapFileInline ? output : sourceMapOptions.sourceMapFullFilename) || '.'),
pathToInput = path.dirname(sourceMapOptions.sourceMapInputFilename || '.');
sourceMapOptions.sourceMapRootpath = path.relative(pathToMap, pathToInput);
}
if (! input) {
console.error("lessc: no input files");
console.error("");
printUsage();
process.exitCode = 1;
return;
}
var ensureDirectory = function (filepath) {
var dir = path.dirname(filepath),
cmd,
existsSync = fs.existsSync || path.existsSync;
if (!existsSync(dir)) {
if (mkdirp === undefined) {
try {mkdirp = require('mkdirp');}
catch(e) { mkdirp = null; }
}
cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
cmd(dir);
}
};
if (options.depends) {
if (!outputbase) {
console.error("option --depends requires an output path to be specified");
process.exitCode = 1;
return;
}
process.stdout.write(outputbase + ": ");
}
if (!sourceMapFileInline) {
var writeSourceMap = function(output, onDone) {
output = output || "";
var filename = sourceMapOptions.sourceMapFullFilename;
ensureDirectory(filename);
fs.writeFile(filename, output, 'utf8', function (err) {
if (err) {
var description = "Error: ";
if (errno && errno.errno[err.errno]) {
description += errno.errno[err.errno].description;
} else {
description += err.code + " " + err.message;
}
console.error('lessc: failed to create file ' + filename);
console.error(description);
process.exitCode = 1;
} else {
less.logger.info('lessc: wrote ' + filename);
}
onDone();
});
};
}
var writeSourceMapIfNeeded = function(output, onDone) {
if (options.sourceMap && !sourceMapFileInline) {
writeSourceMap(output, onDone);
} else {
onDone();
}
};
var writeOutput = function(output, result, onSuccess) {
if (options.depends) {
onSuccess();
} else if (output) {
ensureDirectory(output);
fs.writeFile(output, result.css, {encoding: 'utf8'}, function (err) {
if (err) {
var description = "Error: ";
if (errno && errno.errno[err.errno]) {
description += errno.errno[err.errno].description;
} else {
description += err.code + " " + err.message;
}
console.error('lessc: failed to create file ' + output);
console.error(description);
process.exitCode = 1;
} else {
less.logger.info('lessc: wrote ' + output);
onSuccess();
}
});
} else if (!options.depends) {
process.stdout.write(result.css);
onSuccess();
}
};
var logDependencies = function(options, result) {
if (options.depends) {
var depends = "";
for (var i = 0; i < result.imports.length; i++) {
depends += result.imports[i] + " ";
}
console.log(depends);
}
};
var parseLessFile = function (e, data) {
if (e) {
console.error("lessc: " + e.message);
process.exitCode = 1;
return;
}
data = data.replace(/^\uFEFF/, '');
options.paths = [path.dirname(input)].concat(options.paths);
options.filename = input;
if (options.lint) {
options.sourceMap = false;
}
sourceMapOptions.sourceMapFileInline = sourceMapFileInline;
if (options.sourceMap) {
options.sourceMap = sourceMapOptions;
}
less.logger.addListener({
info: function(msg) {
if (verbose) {
console.log(msg);
}
},
warn: function(msg) {
// do not show warning if the silent option is used
if (!silent) {
console.warn(msg);
}
},
error: function(msg) {
console.error(msg);
}
});
less.render(data, options)
.then(function(result) {
if (!options.lint) {
writeOutput(output, result, function() {
writeSourceMapIfNeeded(result.map, function() {
logDependencies(options, result);
});
});
}
},
function(err) {
less.writeError(err, options);
process.exitCode = 1;
});
};
if (input != '-') {
fs.readFile(input, 'utf8', parseLessFile);
} else {
process.stdin.resume();
process.stdin.setEncoding('utf8');
var buffer = '';
process.stdin.on('data', function(data) {
buffer += data;
});
process.stdin.on('end', function() {
parseLessFile(false, buffer);
});
}
})();

24
static/js/ketcher2/node_modules/less/bower.json generated vendored Normal file
View File

@ -0,0 +1,24 @@
{
"name": "less",
"main": "dist/less.js",
"ignore": [
"**/.*",
"benchmark",
"bin",
"build",
"gradle",
"lib",
"test",
"*.md",
"LICENSE",
"Gruntfile.js",
"*.json",
"*.yml",
"build.gradle",
"gradlew",
"gradlew.bat",
".gitattributes",
".jshintrc",
".npmignore"
]
}

1
static/js/ketcher2/node_modules/less/browser.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = require('./lib/less-browser');

347
static/js/ketcher2/node_modules/less/build.gradle generated vendored Normal file
View File

@ -0,0 +1,347 @@
import groovy.io.FileType
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.tasks.Exec
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.eriwen:gradle-js-plugin:1.8.0'
classpath 'com.moowork.gradle:gradle-grunt-plugin:0.2'
}
}
apply plugin: 'js'
apply plugin: 'grunt'
repositories {
mavenCentral()
}
configurations {
rhino
}
dependencies {
rhino 'org.mozilla:rhino:1.7R4'
}
project.ext {
packageProps = new groovy.json.JsonSlurper().parseText(new File("package.json").toURL().text)
failures = 0;
rhinoTestSrc = "out/rhino-test-${packageProps.version}.js"
testSrc = 'test/less'
testOut = 'out/test'
}
task runGruntRhino(type: GruntTask) {
gruntArgs = "rhino"
}
combineJs {
dependsOn runGruntRhino
source = ["dist/less-rhino-${packageProps.version}.js", "test/rhino/test-header.js","dist/lessc-rhino-${packageProps.version}.js"]
dest = file(rhinoTestSrc)
}
task testRhino(type: AllRhinoTests) {
// dependsOn 'testRhinoBase'
dependsOn 'testRhinoBase', 'testRhinoErrors', 'testRhinoLegacy', 'testRhinoStaticUrls', 'testRhinoCompression', 'testRhinoDebugAll', 'testRhinoDebugComments', 'testRhinoDebugMediaquery', 'testRhinoNoJsError', 'testRhinoSourceMap'
}
task testRhinoBase(type: RhinoTest) {
options = [ '--strict-math=true', '--relative-urls' ]
}
task testRhinoDebugAll(type: DebugRhinoTest) {
options = [ '--strict-math=true', '--line-numbers=all' ]
testDir = 'debug' + fs
suffix = "-all"
}
task testRhinoDebugComments(type: DebugRhinoTest) {
options = [ '--strict-math=true', '--line-numbers=comments' ]
testDir = 'debug' + fs
suffix = "-comments"
}
task testRhinoDebugMediaquery(type: DebugRhinoTest) {
options = [ '--strict-math=true', '--line-numbers=mediaquery' ]
testDir = 'debug' + fs
suffix = "-mediaquery"
}
task testRhinoErrors(type: RhinoTest) {
options = [ '--strict-math=true', '--strict-units=true' ]
testDir = 'errors/'
expectErrors = true
}
task testRhinoChyby(type: RhinoTest) {
options = [ '--strict-math=true', '--strict-units=true' ]
testDir = 'chyby/'
// expectErrors = true
}
task testRhinoNoJsError(type: RhinoTest) {
options = [ '--strict-math=true', '--strict-units=true', '--no-js' ]
testDir = 'no-js-errors/'
expectErrors = true
}
task testRhinoLegacy(type: RhinoTest) {
testDir = 'legacy/'
}
task testRhinoStaticUrls(type: RhinoTest) {
options = [ '--strict-math=true', '--rootpath=folder (1)/' ]
testDir = 'static-urls/'
}
task testRhinoCompression(type: RhinoTest) {
options = [ '--compress=true' ]
testDir = 'compression/'
}
task testRhinoSourceMap(type: SourceMapRhinoTest) {
options = [ '--strict-math=true', '--strict-units=true']
testDir = 'sourcemaps/'
}
task setupTest {
dependsOn combineJs
doLast {
file(testOut).deleteDir()
}
}
task clean << {
file(rhinoTestSrc).delete()
file(testOut).deleteDir()
}
class SourceMapRhinoTest extends RhinoTest {
// helper to get the output map file
def getOutputMap(lessFile) {
def outFile = project.file(lessFile.path.replace('test/less', project.testOut).replace('.less', '.css'))
return project.file(outFile.path + ".map");
}
// callback to add SourceMap options to the options list
def postProcessOptions(options, lessFile) {
def outFile = getOutputMap(lessFile)
project.file(outFile.parent).mkdirs()
options << "--source-map=${testDir}${lessFile.name.replace('.less','.css')}"
options << "--source-map-basepath=${lessRootDir}"
options << "--source-map-rootpath=testweb/"
options << "--source-map-output-map-file=${outFile}"
options
}
// Callback to validate output
def handleResult(exec, out, lessFile) {
def actualFile = getOutputMap(lessFile)
def expectedFile = project.file(projectDir + fs + "test" + fs + testDir + fs + lessFile.name.replace(".less", ".json"))
assert actualFile.text == expectedFile.text
}
}
class DebugRhinoTest extends RhinoTest {
def escapeIt(it) {
return it.replaceAll("\\\\", "\\\\\\\\").replaceAll("/", "\\\\/").replaceAll(":", "\\\\:").replaceAll("\\.", "\\\\.");
}
def globalReplacements(input, directory) {
def pDirectory = toPlatformFs(directory)
def p = lessRootDir + fs + pDirectory
def pathimport = p + toPlatformFs("import/")
def pathesc = escapeIt(p)
def pathimportesc = escapeIt(pathimport)
def result = input.replace("{path}", p).replace("{pathesc}", pathesc).replace("{pathimport}", pathimport)
return result.replace("{pathimportesc}", pathimportesc).replace("\r\n", "\n")
}
}
class RhinoTest extends DefaultTask {
RhinoTest() {
dependsOn 'setupTest'
}
def suffix = ""
def testDir = ''
def options = []
def expectErrors = false
def fs = File.separator;
def projectDir = toUpperCaseDriveLetter(System.getProperty("user.dir"));
def lessRootDir = projectDir + fs + "test" + fs + "less"
def toUpperCaseDriveLetter(path) {
if (path.charAt(1)==':' && path.charAt(2)=='\\') {
return path.substring(0,1).toUpperCase() + path.substring(1);
}
return path;
}
def toPlatformFs(path) {
return path.replace('\\', fs).replace('/', fs);
}
def expectedCssPath(lessFilePath) {
lessFilePath.replace('.less', "${suffix}.css").replace("${fs}less${fs}", "${fs}css${fs}");
}
def globalReplacements(input, directory) {
return input;
}
def stylize(str, style) {
def styles = [
reset : [0, 0],
bold : [1, 22],
inverse : [7, 27],
underline : [4, 24],
yellow : [33, 39],
green : [32, 39],
red : [31, 39],
grey : [90, 39]
];
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
}
// Callback for subclasses to make any changes to the options
def postProcessOptions(options, lessFile) {
options
}
// Callback to validate output
def handleResult(exec, out, lessFile) {
def actual = out.toString().trim()
def actualResult = project.file(lessFile.path.replace('test/less', project.testOut).replace('.less', '.css'))
project.file(actualResult.parent).mkdirs()
actualResult << actual
def expected
if (expectErrors) {
assert exec.exitValue != 0
expected = project.file(lessFile.path.replace('.less', '.txt')).text.trim().
replace('{path}', lessFile.parent + '/').
replace('{pathhref}', '').
replace('{404status}', '')
} else {
assert exec.exitValue == 0
def expectedFile = expectedCssPath(lessFile.path)
expected = project.file(expectedFile).text.trim()
expected = globalReplacements(expected, testDir)
}
actual=actual.trim()
actual = actual.replace('\r\n', '\n')
expected = expected.replace('\r\n', '\n')
actual = actual.replace("/","\\")
expected = expected.replace("/","\\")
// println "* actual *"
// println actual
// new File("actual.txt").write(actual)
// println "* expected *"
// println expected
// new File("expected.txt").write(expected)
assert actual == expected
actualResult.delete()
}
@TaskAction
def runTest() {
int testSuccesses = 0, testFailures = 0, testErrors = 0
project.file('test/less/' + testDir).eachFileMatch(FileType.FILES, ~/.*\.less/) { lessFile ->
println "lessfile: $lessFile"
if (!project.hasProperty('test') || lessFile.name.startsWith(project.test)) {
def out = new java.io.ByteArrayOutputStream()
def processedOptions = postProcessOptions([project.rhinoTestSrc, lessFile] + options, lessFile)
def execOptions = {
main = 'org.mozilla.javascript.tools.shell.Main'
// main = 'org.mozilla.javascript.tools.debugger.Main'
classpath = project.configurations.rhino
args = processedOptions
standardOutput = out
ignoreExitValue = true
}
println "rhinoTestSrc: ${project.rhinoTestSrc}"
try {
def exec = project.javaexec(execOptions)
handleResult(exec, out, lessFile)
testSuccesses++
println stylize(' ok', 'green')
}
catch (ex) {
println ex
println()
testErrors++;
}
catch (AssertionError ae) {
println stylize(' failed', 'red')
println ae
testFailures++
}
} else {
println stylize(' skipped', 'yellow')
}
}
println stylize(testSuccesses + ' ok', 'green')
println stylize(testFailures + ' assertion failed', testFailures == 0 ? 'green' : 'red')
println stylize(testErrors + ' errors', testErrors == 0 ? 'green' : 'red')
if (testFailures != 0 || testErrors != 0) {
project.failures++;
}
}
}
class AllRhinoTests extends DefaultTask {
AllRhinoTests() {
}
@TaskAction
def runTest() {
println stylize(project.failures + ' test suites failed', project.failures == 0 ? 'green' : 'red')
}
def stylize(str, style) {
def styles = [
reset : [0, 0],
bold : [1, 22],
inverse : [7, 27],
underline : [4, 24],
yellow : [33, 39],
green : [32, 39],
red : [31, 39],
grey : [90, 39]
];
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
}
}
class GruntTask extends Exec {
private String gruntExecutable = Os.isFamily(Os.FAMILY_WINDOWS) ? "grunt.cmd" : "grunt"
private String switches = "--no-color"
String gruntArgs = ""
public GruntTask() {
super()
this.setExecutable(gruntExecutable)
}
public void setGruntArgs(String gruntArgs) {
this.args = "$switches $gruntArgs".trim().split(" ") as List
}
}

10835
static/js/ketcher2/node_modules/less/dist/less.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

17
static/js/ketcher2/node_modules/less/dist/less.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

164
static/js/ketcher2/node_modules/less/gradlew generated vendored Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
static/js/ketcher2/node_modules/less/gradlew.bat generated vendored Normal file
View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
static/js/ketcher2/node_modules/less/index.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = require('./lib/less-node');

View File

@ -0,0 +1,46 @@
var addDataAttr = require("./utils").addDataAttr,
browser = require("./browser");
module.exports = function(window, options) {
// use options from the current script tag data attribues
addDataAttr(options, browser.currentScript(window));
if (options.isFileProtocol === undefined) {
options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol);
}
// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
options.async = options.async || false;
options.fileAsync = options.fileAsync || false;
// Interval between watch polls
options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500);
options.env = options.env || (window.location.hostname == '127.0.0.1' ||
window.location.hostname == '0.0.0.0' ||
window.location.hostname == 'localhost' ||
(window.location.port &&
window.location.port.length > 0) ||
options.isFileProtocol ? 'development'
: 'production');
var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash);
if (dumpLineNumbers) {
options.dumpLineNumbers = dumpLineNumbers[1];
}
if (options.useFileCache === undefined) {
options.useFileCache = true;
}
if (options.onReady === undefined) {
options.onReady = true;
}
};

View File

@ -0,0 +1,51 @@
/**
* Kicks off less and compiles any stylesheets
* used in the browser distributed version of less
* to kick-start less using the browser api
*/
/*global window, document */
// shim Promise if required
require('promise/polyfill.js');
var options = window.less || {};
require("./add-default-options")(window, options);
var less = module.exports = require("./index")(window, options);
window.less = less;
var css, head, style;
// Always restore page visibility
function resolveOrReject(data) {
if (data.filename) {
console.warn(data);
}
if (!options.async) {
head.removeChild(style);
}
}
if (options.onReady) {
if (/!watch/.test(window.location.hash)) {
less.watch();
}
// Simulate synchronous stylesheet loading by blocking page rendering
if (!options.async) {
css = 'body { display: none !important }';
head = document.head || document.getElementsByTagName('head')[0];
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
less.registerStylesheetsImmediately();
less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject);
}

View File

@ -0,0 +1,64 @@
var utils = require("./utils");
module.exports = {
createCSS: function (document, styles, sheet) {
// Strip the query-string
var href = sheet.href || '';
// If there is no title set, use the filename, minus the extension
var id = 'less:' + (sheet.title || utils.extractId(href));
// If this has already been inserted into the DOM, we may need to replace it
var oldStyleNode = document.getElementById(id);
var keepOldStyleNode = false;
// Create a new stylesheet node for insertion or (if necessary) replacement
var styleNode = document.createElement('style');
styleNode.setAttribute('type', 'text/css');
if (sheet.media) {
styleNode.setAttribute('media', sheet.media);
}
styleNode.id = id;
if (!styleNode.styleSheet) {
styleNode.appendChild(document.createTextNode(styles));
// If new contents match contents of oldStyleNode, don't replace oldStyleNode
keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 &&
oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue);
}
var head = document.getElementsByTagName('head')[0];
// If there is no oldStyleNode, just append; otherwise, only append if we need
// to replace oldStyleNode with an updated stylesheet
if (oldStyleNode === null || keepOldStyleNode === false) {
var nextEl = sheet && sheet.nextSibling || null;
if (nextEl) {
nextEl.parentNode.insertBefore(styleNode, nextEl);
} else {
head.appendChild(styleNode);
}
}
if (oldStyleNode && keepOldStyleNode === false) {
oldStyleNode.parentNode.removeChild(oldStyleNode);
}
// For IE.
// This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash.
// See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head
if (styleNode.styleSheet) {
try {
styleNode.styleSheet.cssText = styles;
} catch (e) {
throw new Error("Couldn't reassign styleSheet.cssText.");
}
}
},
currentScript: function(window) {
var document = window.document;
return document.currentScript || (function() {
var scripts = document.getElementsByTagName("script");
return scripts[scripts.length - 1];
})();
}
};

View File

@ -0,0 +1,42 @@
// Cache system is a bit outdated and could do with work
module.exports = function(window, options, logger) {
var cache = null;
if (options.env !== 'development') {
try {
cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage;
} catch (_) {}
}
return {
setCSS: function(path, lastModified, modifyVars, styles) {
if (cache) {
logger.info('saving ' + path + ' to cache.');
try {
cache.setItem(path, styles);
cache.setItem(path + ':timestamp', lastModified);
if (modifyVars) {
cache.setItem(path + ':vars', JSON.stringify(modifyVars));
}
} catch(e) {
//TODO - could do with adding more robust error handling
logger.error('failed to save "' + path + '" to local storage for caching.');
}
}
},
getCSS: function(path, webInfo, modifyVars) {
var css = cache && cache.getItem(path),
timestamp = cache && cache.getItem(path + ':timestamp'),
vars = cache && cache.getItem(path + ':vars');
modifyVars = modifyVars || {};
if (timestamp && webInfo.lastModified &&
(new Date(webInfo.lastModified).valueOf() ===
new Date(timestamp).valueOf()) &&
(!modifyVars && !vars || JSON.stringify(modifyVars) === vars)) {
// Use local copy
return css;
}
}
};
};

View File

@ -0,0 +1,170 @@
var utils = require("./utils"),
browser = require("./browser");
module.exports = function(window, less, options) {
function errorHTML(e, rootHref) {
var id = 'less-error-message:' + utils.extractId(rootHref || "");
var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
var elem = window.document.createElement('div'), timer, content, errors = [];
var filename = e.filename || rootHref;
var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
elem.id = id;
elem.className = "less-error-message";
content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
'</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
var errorline = function (e, i, classname) {
if (e.extract[i] !== undefined) {
errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
}
};
if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
'<ul>' + errors.join('') + '</ul>';
}
if (e.stack && (e.extract || options.logLevel >= 4)) {
content += '<br/>Stack Trace</br />' + e.stack.split('\n').slice(1).join('<br/>');
}
elem.innerHTML = content;
// CSS for error messages
browser.createCSS(window.document, [
'.less-error-message ul, .less-error-message li {',
'list-style-type: none;',
'margin-right: 15px;',
'padding: 4px 0;',
'margin: 0;',
'}',
'.less-error-message label {',
'font-size: 12px;',
'margin-right: 15px;',
'padding: 4px 0;',
'color: #cc7777;',
'}',
'.less-error-message pre {',
'color: #dd6666;',
'padding: 4px 0;',
'margin: 0;',
'display: inline-block;',
'}',
'.less-error-message pre.line {',
'color: #ff0000;',
'}',
'.less-error-message h3 {',
'font-size: 20px;',
'font-weight: bold;',
'padding: 15px 0 5px 0;',
'margin: 0;',
'}',
'.less-error-message a {',
'color: #10a',
'}',
'.less-error-message .error {',
'color: red;',
'font-weight: bold;',
'padding-bottom: 2px;',
'border-bottom: 1px dashed red;',
'}'
].join('\n'), { title: 'error-message' });
elem.style.cssText = [
"font-family: Arial, sans-serif",
"border: 1px solid #e00",
"background-color: #eee",
"border-radius: 5px",
"-webkit-border-radius: 5px",
"-moz-border-radius: 5px",
"color: #e00",
"padding: 15px",
"margin-bottom: 15px"
].join(';');
if (options.env === 'development') {
timer = setInterval(function () {
var document = window.document,
body = document.body;
if (body) {
if (document.getElementById(id)) {
body.replaceChild(elem, document.getElementById(id));
} else {
body.insertBefore(elem, body.firstChild);
}
clearInterval(timer);
}
}, 10);
}
}
function removeErrorHTML(path) {
var node = window.document.getElementById('less-error-message:' + utils.extractId(path));
if (node) {
node.parentNode.removeChild(node);
}
}
function removeErrorConsole(path) {
//no action
}
function removeError(path) {
if (!options.errorReporting || options.errorReporting === "html") {
removeErrorHTML(path);
} else if (options.errorReporting === "console") {
removeErrorConsole(path);
} else if (typeof options.errorReporting === 'function') {
options.errorReporting("remove", path);
}
}
function errorConsole(e, rootHref) {
var template = '{line} {content}';
var filename = e.filename || rootHref;
var errors = [];
var content = (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
" in " + filename + " ";
var errorline = function (e, i, classname) {
if (e.extract[i] !== undefined) {
errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
}
};
if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
errors.join('\n');
}
if (e.stack && (e.extract || options.logLevel >= 4)) {
content += '\nStack Trace\n' + e.stack;
}
less.logger.error(content);
}
function error(e, rootHref) {
if (!options.errorReporting || options.errorReporting === "html") {
errorHTML(e, rootHref);
} else if (options.errorReporting === "console") {
errorConsole(e, rootHref);
} else if (typeof options.errorReporting === 'function') {
options.errorReporting("add", e, rootHref);
}
}
return {
add: error,
remove: removeError
};
};

View File

@ -0,0 +1,119 @@
/*global window, XMLHttpRequest */
module.exports = function(options, logger) {
var AbstractFileManager = require("../less/environment/abstract-file-manager.js");
var fileCache = {};
//TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
function getXMLHttpRequest() {
if (window.XMLHttpRequest && (window.location.protocol !== "file:" || !("ActiveXObject" in window))) {
return new XMLHttpRequest();
} else {
try {
/*global ActiveXObject */
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
logger.error("browser doesn't support AJAX.");
return null;
}
}
}
var FileManager = function() {
};
FileManager.prototype = new AbstractFileManager();
FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() {
return true;
};
FileManager.prototype.join = function join(basePath, laterPath) {
if (!basePath) {
return laterPath;
}
return this.extractUrlParts(laterPath, basePath).path;
};
FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) {
var xhr = getXMLHttpRequest();
var async = options.isFileProtocol ? options.fileAsync : true;
if (typeof xhr.overrideMimeType === 'function') {
xhr.overrideMimeType('text/css');
}
logger.debug("XHR: Getting '" + url + "'");
xhr.open('GET', url, async);
xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
xhr.send(null);
function handleResponse(xhr, callback, errback) {
if (xhr.status >= 200 && xhr.status < 300) {
callback(xhr.responseText,
xhr.getResponseHeader("Last-Modified"));
} else if (typeof errback === 'function') {
errback(xhr.status, url);
}
}
if (options.isFileProtocol && !options.fileAsync) {
if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
callback(xhr.responseText);
} else {
errback(xhr.status, url);
}
} else if (async) {
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
handleResponse(xhr, callback, errback);
}
};
} else {
handleResponse(xhr, callback, errback);
}
};
FileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
return true;
};
FileManager.prototype.clearFileCache = function() {
fileCache = {};
};
FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment, callback) {
if (currentDirectory && !this.isPathAbsolute(filename)) {
filename = currentDirectory + filename;
}
options = options || {};
// sheet may be set to the stylesheet for the initial load or a collection of properties including
// some context variables for imports
var hrefParts = this.extractUrlParts(filename, window.location.href);
var href = hrefParts.url;
if (options.useFileCache && fileCache[href]) {
try {
var lessText = fileCache[href];
callback(null, { contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
} catch (e) {
callback({filename: href, message: "Error loading file " + href + " error was " + e.message});
}
return;
}
this.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
// per file cache
fileCache[href] = data;
// Use remote copy (re-parse)
callback(null, { contents: data, filename: href, webInfo: { lastModified: lastModified }});
}, function doXHRError(status, url) {
callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")", href: href });
});
};
return FileManager;
};

View File

@ -0,0 +1,28 @@
module.exports = function() {
var functionRegistry = require("./../less/functions/function-registry");
function imageSize() {
throw {
type: "Runtime",
message: "Image size functions are not supported in browser version of less"
};
}
var imageFunctions = {
"image-size": function(filePathNode) {
imageSize(this, filePathNode);
return -1;
},
"image-width": function(filePathNode) {
imageSize(this, filePathNode);
return -1;
},
"image-height": function(filePathNode) {
imageSize(this, filePathNode);
return -1;
}
};
functionRegistry.addMultiple(imageFunctions);
};

View File

@ -0,0 +1,286 @@
//
// index.js
// Should expose the additional browser functions on to the less object
//
var addDataAttr = require("./utils").addDataAttr,
browser = require("./browser");
module.exports = function(window, options) {
var document = window.document;
var less = require('../less')();
//module.exports = less;
less.options = options;
var environment = less.environment,
FileManager = require("./file-manager")(options, less.logger),
fileManager = new FileManager();
environment.addFileManager(fileManager);
less.FileManager = FileManager;
require("./log-listener")(less, options);
var errors = require("./error-reporting")(window, less, options);
var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
require('./image-size')(less.environment);
//Setup user functions
if (options.functions) {
less.functions.functionRegistry.addMultiple(options.functions);
}
var typePattern = /^text\/(x-)?less$/;
function postProcessCSS(styles) { // deprecated, use a plugin for postprocesstasks
if (options.postProcessor && typeof options.postProcessor === 'function') {
styles = options.postProcessor.call(styles, styles) || styles;
}
return styles;
}
function clone(obj) {
var cloned = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
cloned[prop] = obj[prop];
}
}
return cloned;
}
// only really needed for phantom
function bind(func, thisArg) {
var curryArgs = Array.prototype.slice.call(arguments, 2);
return function() {
var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
return func.apply(thisArg, args);
};
}
function loadStyles(modifyVars) {
var styles = document.getElementsByTagName('style'),
style;
for (var i = 0; i < styles.length; i++) {
style = styles[i];
if (style.type.match(typePattern)) {
var instanceOptions = clone(options);
instanceOptions.modifyVars = modifyVars;
var lessText = style.innerHTML || '';
instanceOptions.filename = document.location.href.replace(/#.*$/, '');
/*jshint loopfunc:true */
// use closure to store current style
less.render(lessText, instanceOptions,
bind(function(style, e, result) {
if (e) {
errors.add(e, "inline");
} else {
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = result.css;
} else {
style.innerHTML = result.css;
}
}
}, null, style));
}
}
}
function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
var instanceOptions = clone(options);
addDataAttr(instanceOptions, sheet);
instanceOptions.mime = sheet.type;
if (modifyVars) {
instanceOptions.modifyVars = modifyVars;
}
function loadInitialFileCallback(loadedFile) {
var data = loadedFile.contents,
path = loadedFile.filename,
webInfo = loadedFile.webInfo;
var newFileInfo = {
currentDirectory: fileManager.getPath(path),
filename: path,
rootFilename: path,
relativeUrls: instanceOptions.relativeUrls};
newFileInfo.entryPath = newFileInfo.currentDirectory;
newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
if (webInfo) {
webInfo.remaining = remaining;
var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
if (!reload && css) {
webInfo.local = true;
callback(null, css, data, sheet, webInfo, path);
return;
}
}
//TODO add tests around how this behaves when reloading
errors.remove(path);
instanceOptions.rootFileInfo = newFileInfo;
less.render(data, instanceOptions, function(e, result) {
if (e) {
e.href = path;
callback(e);
} else {
result.css = postProcessCSS(result.css);
cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
callback(null, result.css, data, sheet, webInfo, path);
}
});
}
fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
if (e) {
callback(e);
return;
}
loadInitialFileCallback(loadedFile);
});
}
function loadStyleSheets(callback, reload, modifyVars) {
for (var i = 0; i < less.sheets.length; i++) {
loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
}
}
function initRunningMode() {
if (less.env === 'development') {
less.watchTimer = setInterval(function () {
if (less.watchMode) {
fileManager.clearFileCache();
loadStyleSheets(function (e, css, _, sheet, webInfo) {
if (e) {
errors.add(e, e.href || sheet.href);
} else if (css) {
browser.createCSS(window.document, css, sheet);
}
});
}
}, options.poll);
}
}
//
// Watch mode
//
less.watch = function () {
if (!less.watchMode ) {
less.env = 'development';
initRunningMode();
}
this.watchMode = true;
return true;
};
less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
//
// Synchronously get all <link> tags with the 'rel' attribute set to
// "stylesheet/less".
//
less.registerStylesheetsImmediately = function() {
var links = document.getElementsByTagName('link');
less.sheets = [];
for (var i = 0; i < links.length; i++) {
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
(links[i].type.match(typePattern)))) {
less.sheets.push(links[i]);
}
}
};
//
// Asynchronously get all <link> tags with the 'rel' attribute set to
// "stylesheet/less", returning a Promise.
//
less.registerStylesheets = function() {
return new Promise(function(resolve, reject) {
less.registerStylesheetsImmediately();
resolve();
});
};
//
// With this function, it's possible to alter variables and re-render
// CSS without reloading less-files
//
less.modifyVars = function(record) {
return less.refresh(true, record, false);
};
less.refresh = function (reload, modifyVars, clearFileCache) {
if ((reload || clearFileCache) && clearFileCache !== false) {
fileManager.clearFileCache();
}
return new Promise(function (resolve, reject) {
var startTime, endTime, totalMilliseconds, remainingSheets;
startTime = endTime = new Date();
// Set counter for remaining unprocessed sheets
remainingSheets = less.sheets.length;
if (remainingSheets === 0) {
endTime = new Date();
totalMilliseconds = endTime - startTime;
less.logger.info("Less has finished and no sheets were loaded.");
resolve({
startTime: startTime,
endTime: endTime,
totalMilliseconds: totalMilliseconds,
sheets: less.sheets.length
});
} else {
// Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
loadStyleSheets(function (e, css, _, sheet, webInfo) {
if (e) {
errors.add(e, e.href || sheet.href);
reject(e);
return;
}
if (webInfo.local) {
less.logger.info("Loading " + sheet.href + " from cache.");
} else {
less.logger.info("Rendered " + sheet.href + " successfully.");
}
browser.createCSS(window.document, css, sheet);
less.logger.info("CSS for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
// Count completed sheet
remainingSheets--;
// Check if the last remaining sheet was processed and then call the promise
if (remainingSheets === 0) {
totalMilliseconds = new Date() - startTime;
less.logger.info("Less has finished. CSS generated in " + totalMilliseconds + 'ms');
resolve({
startTime: startTime,
endTime: endTime,
totalMilliseconds: totalMilliseconds,
sheets: less.sheets.length
});
}
endTime = new Date();
}, reload, modifyVars);
}
loadStyles(modifyVars);
});
};
less.refreshStyles = loadStyles;
return less;
};

View File

@ -0,0 +1,43 @@
module.exports = function(less, options) {
var logLevel_debug = 4,
logLevel_info = 3,
logLevel_warn = 2,
logLevel_error = 1;
// The amount of logging in the javascript console.
// 3 - Debug, information and errors
// 2 - Information and errors
// 1 - Errors
// 0 - None
// Defaults to 2
options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);
if (!options.loggers) {
options.loggers = [{
debug: function(msg) {
if (options.logLevel >= logLevel_debug) {
console.log(msg);
}
},
info: function(msg) {
if (options.logLevel >= logLevel_info) {
console.log(msg);
}
},
warn: function(msg) {
if (options.logLevel >= logLevel_warn) {
console.warn(msg);
}
},
error: function(msg) {
if (options.logLevel >= logLevel_error) {
console.error(msg);
}
}
}];
}
for (var i = 0; i < options.loggers.length; i++) {
less.logger.addListener(options.loggers[i]);
}
};

View File

@ -0,0 +1,24 @@
module.exports = {
extractId: function(href) {
return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain
.replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster
.replace(/^\//, '') // Remove root /
.replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
},
addDataAttr: function(options, tag) {
for (var opt in tag.dataset) {
if (tag.dataset.hasOwnProperty(opt)) {
if (opt === "env" || opt === "dumpLineNumbers" || opt === "rootpath" || opt === "errorReporting") {
options[opt] = tag.dataset[opt];
} else {
try {
options[opt] = JSON.parse(tag.dataset[opt]);
}
catch(_) {}
}
}
}
}
};

View File

@ -0,0 +1,14 @@
module.exports = {
encodeBase64: function encodeBase64(str) {
return new Buffer(str).toString('base64');
},
mimeLookup: function (filename) {
return require('mime').lookup(filename);
},
charsetLookup: function (mime) {
return require('mime').charsets.lookup(mime);
},
getSourceMapGenerator: function getSourceMapGenerator() {
return require("source-map").SourceMapGenerator;
}
};

View File

@ -0,0 +1,108 @@
var path = require('path'),
fs = require('./fs'),
PromiseConstructor,
AbstractFileManager = require("../less/environment/abstract-file-manager.js");
try {
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
} catch(e) {
}
var FileManager = function() {
};
FileManager.prototype = new AbstractFileManager();
FileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
return true;
};
FileManager.prototype.supportsSync = function(filename, currentDirectory, options, environment) {
return true;
};
FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) {
var fullFilename,
data,
isAbsoluteFilename = this.isPathAbsolute(filename),
filenamesTried = [];
options = options || {};
if (options.syncImport || !PromiseConstructor) {
data = this.loadFileSync(filename, currentDirectory, options, environment, 'utf-8');
callback(data.error, data);
return;
}
var paths = isAbsoluteFilename ? [""] : [currentDirectory];
if (options.paths) { paths.push.apply(paths, options.paths); }
if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
// promise is guaranteed to be asyncronous
// which helps as it allows the file handle
// to be closed before it continues with the next file
return new PromiseConstructor(function(fulfill, reject) {
(function tryPathIndex(i) {
if (i < paths.length) {
fullFilename = filename;
if (paths[i]) {
fullFilename = path.join(paths[i], fullFilename);
}
fs.stat(fullFilename, function (err) {
if (err) {
filenamesTried.push(fullFilename);
tryPathIndex(i + 1);
} else {
fs.readFile(fullFilename, 'utf-8', function(e, data) {
if (e) { reject(e); return; }
fulfill({ contents: data, filename: fullFilename});
});
}
});
} else {
reject({ type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") });
}
}(0));
});
};
FileManager.prototype.loadFileSync = function(filename, currentDirectory, options, environment, encoding) {
var fullFilename, paths, filenamesTried = [], isAbsoluteFilename = this.isPathAbsolute(filename) , data;
options = options || {};
paths = isAbsoluteFilename ? [""] : [currentDirectory];
if (options.paths) {
paths.push.apply(paths, options.paths);
}
if (!isAbsoluteFilename && paths.indexOf('.') === -1) {
paths.push('.');
}
var err, result;
for (var i = 0; i < paths.length; i++) {
try {
fullFilename = filename;
if (paths[i]) {
fullFilename = path.join(paths[i], fullFilename);
}
filenamesTried.push(fullFilename);
fs.statSync(fullFilename);
break;
} catch (e) {
fullFilename = null;
}
}
if (!fullFilename) {
err = { type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") };
result = { error: err };
} else {
data = fs.readFileSync(fullFilename, encoding);
result = { contents: data, filename: fullFilename};
}
return result;
};
module.exports = FileManager;

View File

@ -0,0 +1,10 @@
var fs;
try
{
fs = require("graceful-fs");
}
catch(e)
{
fs = require("fs");
}
module.exports = fs;

View File

@ -0,0 +1,57 @@
module.exports = function(environment) {
var Dimension = require("../less/tree/dimension"),
Expression = require("../less/tree/expression"),
functionRegistry = require("./../less/functions/function-registry");
function imageSize(functionContext, filePathNode) {
var filePath = filePathNode.value;
var currentFileInfo = functionContext.currentFileInfo;
var currentDirectory = currentFileInfo.relativeUrls ?
currentFileInfo.currentDirectory : currentFileInfo.entryPath;
var fragmentStart = filePath.indexOf('#');
var fragment = '';
if (fragmentStart !== -1) {
fragment = filePath.slice(fragmentStart);
filePath = filePath.slice(0, fragmentStart);
}
var fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true);
if (!fileManager) {
throw {
type: "File",
message: "Can not set up FileManager for " + filePathNode
};
}
var fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment);
if (fileSync.error) {
throw fileSync.error;
}
var sizeOf = require('image-size');
return sizeOf(fileSync.filename);
}
var imageFunctions = {
"image-size": function(filePathNode) {
var size = imageSize(this, filePathNode);
return new Expression([
new Dimension(size.width, "px"),
new Dimension(size.height, "px")
]);
},
"image-width": function(filePathNode) {
var size = imageSize(this, filePathNode);
return new Dimension(size.width, "px");
},
"image-height": function(filePathNode) {
var size = imageSize(this, filePathNode);
return new Dimension(size.height, "px");
}
};
functionRegistry.addMultiple(imageFunctions);
};

View File

@ -0,0 +1,74 @@
var environment = require("./environment"),
FileManager = require("./file-manager"),
UrlFileManager = require("./url-file-manager"),
createFromEnvironment = require("../less"),
less = createFromEnvironment(environment, [new FileManager(), new UrlFileManager()]),
lesscHelper = require('./lessc-helper');
// allow people to create less with their own environment
less.createFromEnvironment = createFromEnvironment;
less.lesscHelper = lesscHelper;
less.PluginLoader = require("./plugin-loader");
less.fs = require("./fs");
less.FileManager = FileManager;
less.UrlFileManager = UrlFileManager;
less.formatError = function(ctx, options) {
options = options || {};
var message = "";
var extract = ctx.extract;
var error = [];
var stylize = options.color ? lesscHelper.stylize : function (str) { return str; };
// only output a stack if it isn't a less error
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
if (!ctx.hasOwnProperty('index') || !extract) {
return ctx.stack || ctx.message;
}
if (typeof extract[0] === 'string') {
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
}
if (typeof extract[1] === 'string') {
var errorTxt = ctx.line + ' ';
if (extract[1]) {
errorTxt += extract[1].slice(0, ctx.column) +
stylize(stylize(stylize(extract[1].substr(ctx.column, 1), 'bold') +
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
}
error.push(errorTxt);
}
if (typeof extract[2] === 'string') {
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
}
error = error.join('\n') + stylize('', 'reset') + '\n';
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
if (ctx.filename) {
message += stylize(' in ', 'red') + ctx.filename +
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
}
message += '\n' + error;
if (ctx.callLine) {
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
}
return message;
};
less.writeError = function (ctx, options) {
options = options || {};
if (options.silent) { return; }
console.error(less.formatError(ctx, options));
};
// provide image-size functionality
require('./image-size')(less.environment);
module.exports = less;

View File

@ -0,0 +1,82 @@
// lessc_helper.js
//
// helper functions for lessc
var lessc_helper = {
//Stylize a string
stylize : function(str, style) {
var styles = {
'reset' : [0, 0],
'bold' : [1, 22],
'inverse' : [7, 27],
'underline' : [4, 24],
'yellow' : [33, 39],
'green' : [32, 39],
'red' : [31, 39],
'grey' : [90, 39]
};
return '\x1b[' + styles[style][0] + 'm' + str +
'\x1b[' + styles[style][1] + 'm';
},
//Print command line options
printUsage: function() {
console.log("usage: lessc [option option=parameter ...] <source> [destination]");
console.log("");
console.log("If source is set to `-' (dash or hyphen-minus), input is read from stdin.");
console.log("");
console.log("options:");
console.log(" -h, --help Prints help (this message) and exit.");
console.log(" --include-path=PATHS Sets include paths. Separated by `:'. `;' also supported on windows.");
console.log(" -M, --depends Outputs a makefile import dependency list to stdout.");
console.log(" --no-color Disables colorized output.");
console.log(" --no-ie-compat Disables IE compatibility checks.");
console.log(" --no-js Disables JavaScript in less files");
console.log(" -l, --lint Syntax check only (lint).");
console.log(" -s, --silent Suppresses output of error messages.");
console.log(" --strict-imports Forces evaluation of imports.");
console.log(" --insecure Allows imports from insecure https hosts.");
console.log(" -v, --version Prints version number and exit.");
console.log(" --verbose Be verbose.");
console.log(" --source-map[=FILENAME] Outputs a v3 sourcemap to the filename (or output filename.map).");
console.log(" --source-map-rootpath=X Adds this path onto the sourcemap filename and less file paths.");
console.log(" --source-map-basepath=X Sets sourcemap base path, defaults to current working directory.");
console.log(" --source-map-less-inline Puts the less files into the map instead of referencing them.");
console.log(" --source-map-map-inline Puts the map (and any less files) as a base64 data uri into the output css file.");
console.log(" --source-map-url=URL Sets a custom URL to map file, for sourceMappingURL comment");
console.log(" in generated CSS file.");
console.log(" -rp, --rootpath=URL Sets rootpath for url rewriting in relative imports and urls");
console.log(" Works with or without the relative-urls option.");
console.log(" -ru, --relative-urls Re-writes relative urls to the base less file.");
console.log(" -sm=on|off Turns on or off strict math, where in strict mode, math.");
console.log(" --strict-math=on|off Requires brackets. This option may default to on and then");
console.log(" be removed in the future.");
console.log(" -su=on|off Allows mixed units, e.g. 1px+1em or 1px*1px which have units");
console.log(" --strict-units=on|off that cannot be represented.");
console.log(" --global-var='VAR=VALUE' Defines a variable that can be referenced by the file.");
console.log(" --modify-var='VAR=VALUE' Modifies a variable already declared in the file.");
console.log(" --url-args='QUERYSTRING' Adds params into url tokens (e.g. 42, cb=42 or 'a=1&b=2')");
console.log(" --plugin=PLUGIN=OPTIONS Loads a plugin. You can also omit the --plugin= if the plugin begins");
console.log(" less-plugin. E.g. the clean css plugin is called less-plugin-clean-css");
console.log(" once installed (npm install less-plugin-clean-css), use either with");
console.log(" --plugin=less-plugin-clean-css or just --clean-css");
console.log(" specify options afterwards e.g. --plugin=less-plugin-clean-css=\"advanced\"");
console.log(" or --clean-css=\"advanced\"");
console.log("");
console.log("-------------------------- Deprecated ----------------");
console.log(" --line-numbers=TYPE Outputs filename and line numbers.");
console.log(" TYPE can be either 'comments', which will output");
console.log(" the debug info within comments, 'mediaquery'");
console.log(" that will output the information within a fake");
console.log(" media query which is compatible with the SASS");
console.log(" format, and 'all' which will do both.");
console.log(" -x, --compress Compresses output by removing some whitespaces.");
console.log(" We recommend you use a dedicated minifer like less-plugin-clean-css");
console.log("");
console.log("Report bugs to: http://github.com/less/less.js/issues");
console.log("Home page: <http://lesscss.org/>");
}
};
// Exports helper functions
for (var h in lessc_helper) { if (lessc_helper.hasOwnProperty(h)) { exports[h] = lessc_helper[h]; }}

View File

@ -0,0 +1,91 @@
var path = require("path");
/**
* Node Plugin Loader
*/
var PluginLoader = function(less) {
this.less = less;
};
PluginLoader.prototype.tryLoadPlugin = function(name, argument) {
var plugin = this.tryRequirePlugin(name);
if (plugin) {
// support plugins being a function
// so that the plugin can be more usable programmatically
if (typeof plugin === "function") {
plugin = new plugin();
}
if (plugin.minVersion) {
if (this.compareVersion(plugin.minVersion, this.less.version) < 0) {
console.log("plugin " + name + " requires version " + this.versionToString(plugin.minVersion));
return null;
}
}
if (argument) {
if (!plugin.setOptions) {
console.log("options have been provided but the plugin " + name + "does not support any options");
return null;
}
try {
plugin.setOptions(argument);
}
catch(e) {
console.log("Error setting options on plugin " + name);
console.log(e.message);
return null;
}
}
return plugin;
}
return null;
};
PluginLoader.prototype.compareVersion = function(aVersion, bVersion) {
for (var i = 0; i < aVersion.length; i++) {
if (aVersion[i] !== bVersion[i]) {
return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1;
}
}
return 0;
};
PluginLoader.prototype.versionToString = function(version) {
var versionString = "";
for (var i = 0; i < version.length; i++) {
versionString += (versionString ? "." : "") + version[i];
}
return versionString;
};
PluginLoader.prototype.tryRequirePlugin = function(name) {
// is at the same level as the less.js module
try {
return require("../../../" + name);
}
catch(e) {
}
// is installed as a sub dependency of the current folder
try {
return require(path.join(process.cwd(), "node_modules", name));
}
catch(e) {
}
// is referenced relative to the current directory
try {
return require(path.join(process.cwd(), name));
}
catch(e) {
}
// unlikely - would have to be a dependency of where this code was running (less.js)...
if (name[0] !== '.') {
try {
return require(name);
}
catch(e) {
}
}
};
PluginLoader.prototype.printUsage = function(plugins) {
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
if (plugin.printUsage) {
plugin.printUsage();
}
}
};
module.exports = PluginLoader;

View File

@ -0,0 +1,56 @@
var isUrlRe = /^(?:https?:)?\/\//i,
url = require('url'),
request,
PromiseConstructor,
AbstractFileManager = require("../less/environment/abstract-file-manager.js"),
logger = require("../less/logger");
var UrlFileManager = function() {
};
UrlFileManager.prototype = new AbstractFileManager();
UrlFileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
return isUrlRe.test( filename ) || isUrlRe.test(currentDirectory);
};
UrlFileManager.prototype.loadFile = function(filename, currentDirectory, options, environment) {
if (!PromiseConstructor) {
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
}
return new PromiseConstructor(function(fulfill, reject) {
if (request === undefined) {
try { request = require('request'); }
catch(e) { request = null; }
}
if (!request) {
reject({ type: 'File', message: "optional dependency 'request' required to import over http(s)\n" });
return;
}
var urlStr = isUrlRe.test( filename ) ? filename : url.resolve(currentDirectory, filename),
urlObj = url.parse(urlStr);
if (!urlObj.protocol) {
urlObj.protocol = "http";
urlStr = urlObj.format();
}
request.get({uri: urlStr, strictSSL: !options.insecure }, function (error, res, body) {
if (error) {
reject({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n " + error + "\n" });
return;
}
if (res && res.statusCode === 404) {
reject({ type: 'File', message: "resource '" + urlStr + "' was not found\n" });
return;
}
if (!body) {
logger.warn('Warning: Empty body (HTTP ' + res.statusCode + ') returned by "' + urlStr + '"');
}
fulfill({ contents: body, filename: urlStr });
});
});
};
module.exports = UrlFileManager;

View File

@ -0,0 +1,450 @@
/* jshint rhino:true, unused: false */
/* jscs:disable validateIndentation */
/*global name:true, less, loadStyleSheet, os */
function formatError(ctx, options) {
options = options || {};
var message = "";
var extract = ctx.extract;
var error = [];
// var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str; };
var stylize = function (str) { return str; };
// only output a stack if it isn't a less error
if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red'); }
if (!ctx.hasOwnProperty('index') || !extract) {
return ctx.stack || ctx.message;
}
if (typeof extract[0] === 'string') {
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
}
if (typeof extract[1] === 'string') {
var errorTxt = ctx.line + ' ';
if (extract[1]) {
errorTxt += extract[1].slice(0, ctx.column) +
stylize(stylize(stylize(extract[1][ctx.column], 'bold') +
extract[1].slice(ctx.column + 1), 'red'), 'inverse');
}
error.push(errorTxt);
}
if (typeof extract[2] === 'string') {
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
}
error = error.join('\n') + stylize('', 'reset') + '\n';
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
if (ctx.filename) {
message += stylize(' in ', 'red') + ctx.filename +
stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey');
}
message += '\n' + error;
if (ctx.callLine) {
message += stylize('from ', 'red') + (ctx.filename || '') + '/n';
message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n';
}
return message;
}
function writeError(ctx, options) {
options = options || {};
if (options.silent) { return; }
var message = formatError(ctx, options);
throw new Error(message);
}
function loadStyleSheet(sheet, callback, reload, remaining) {
var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')),
sheetName = name.slice(0, endOfPath + 1) + sheet.href,
contents = sheet.contents || {},
input = readFile(sheetName);
input = input.replace(/^\xEF\xBB\xBF/, '');
contents[sheetName] = input;
var parser = new less.Parser({
paths: [sheet.href.replace(/[\w\.-]+$/, '')],
contents: contents
});
parser.parse(input, function (e, root) {
if (e) {
return writeError(e);
}
try {
callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName);
} catch(e) {
writeError(e);
}
});
}
less.Parser.fileLoader = function (file, currentFileInfo, callback, env) {
var href = file;
if (currentFileInfo && currentFileInfo.currentDirectory && !/^\//.test(file)) {
href = less.modules.path.join(currentFileInfo.currentDirectory, file);
}
var path = less.modules.path.dirname(href);
var newFileInfo = {
currentDirectory: path + '/',
filename: href
};
if (currentFileInfo) {
newFileInfo.entryPath = currentFileInfo.entryPath;
newFileInfo.rootpath = currentFileInfo.rootpath;
newFileInfo.rootFilename = currentFileInfo.rootFilename;
newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
} else {
newFileInfo.entryPath = path;
newFileInfo.rootpath = less.rootpath || path;
newFileInfo.rootFilename = href;
newFileInfo.relativeUrls = env.relativeUrls;
}
var j = file.lastIndexOf('/');
if (newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) {
var relativeSubDirectory = file.slice(0, j + 1);
newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file
}
newFileInfo.currentDirectory = path;
newFileInfo.filename = href;
var data = null;
try {
data = readFile(href);
} catch (e) {
callback({ type: 'File', message: "'" + less.modules.path.basename(href) + "' wasn't found" });
return;
}
try {
callback(null, data, href, newFileInfo, { lastModified: 0 });
} catch (e) {
callback(e, null, href);
}
};
function writeFile(filename, content) {
var fstream = new java.io.FileWriter(filename);
var out = new java.io.BufferedWriter(fstream);
out.write(content);
out.close();
}
// Command line integration via Rhino
(function (args) {
var options = {
depends: false,
compress: false,
cleancss: false,
max_line_len: -1,
silent: false,
verbose: false,
lint: false,
paths: [],
color: true,
strictImports: false,
rootpath: '',
relativeUrls: false,
ieCompat: true,
strictMath: false,
strictUnits: false
};
var continueProcessing = true,
currentErrorcode;
var checkArgFunc = function(arg, option) {
if (!option) {
print(arg + " option requires a parameter");
continueProcessing = false;
return false;
}
return true;
};
var checkBooleanArg = function(arg) {
var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg);
if (!onOff) {
print(" unable to parse " + arg + " as a boolean. use one of on/t/true/y/yes/off/f/false/n/no");
continueProcessing = false;
return false;
}
return Boolean(onOff[2]);
};
var warningMessages = "";
var sourceMapFileInline = false;
args = args.filter(function (arg) {
var match = arg.match(/^-I(.+)$/);
if (match) {
options.paths.push(match[1]);
return false;
}
match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=(.*))?$/i);
if (match) {
arg = match[1];
}
else {
return arg;
}
switch (arg) {
case 'v':
case 'version':
console.log("lessc " + less.version.join('.') + " (Less Compiler) [JavaScript]");
continueProcessing = false;
break;
case 'verbose':
options.verbose = true;
break;
case 's':
case 'silent':
options.silent = true;
break;
case 'l':
case 'lint':
options.lint = true;
break;
case 'strict-imports':
options.strictImports = true;
break;
case 'h':
case 'help':
//TODO
// require('../lib/less/lessc_helper').printUsage();
continueProcessing = false;
break;
case 'x':
case 'compress':
options.compress = true;
break;
case 'M':
case 'depends':
options.depends = true;
break;
case 'yui-compress':
warningMessages += "yui-compress option has been removed. assuming clean-css.";
options.cleancss = true;
break;
case 'clean-css':
options.cleancss = true;
break;
case 'max-line-len':
if (checkArgFunc(arg, match[2])) {
options.maxLineLen = parseInt(match[2], 10);
if (options.maxLineLen <= 0) {
options.maxLineLen = -1;
}
}
break;
case 'no-color':
options.color = false;
break;
case 'no-ie-compat':
options.ieCompat = false;
break;
case 'no-js':
options.javascriptEnabled = false;
break;
case 'include-path':
if (checkArgFunc(arg, match[2])) {
// support for both ; and : path separators
// even on windows when using absolute paths with drive letters (eg C:\path:D:\path)
options.paths = match[2]
.split(os.type().match(/Windows/) ? /:(?!\\)|;/ : ':')
.map(function(p) {
if (p) {
// return path.resolve(process.cwd(), p);
return p;
}
});
}
break;
case 'line-numbers':
if (checkArgFunc(arg, match[2])) {
options.dumpLineNumbers = match[2];
}
break;
case 'source-map':
if (!match[2]) {
options.sourceMap = true;
} else {
options.sourceMap = match[2];
}
break;
case 'source-map-rootpath':
if (checkArgFunc(arg, match[2])) {
options.sourceMapRootpath = match[2];
}
break;
case 'source-map-basepath':
if (checkArgFunc(arg, match[2])) {
options.sourceMapBasepath = match[2];
}
break;
case 'source-map-map-inline':
sourceMapFileInline = true;
options.sourceMap = true;
break;
case 'source-map-less-inline':
options.outputSourceFiles = true;
break;
case 'source-map-url':
if (checkArgFunc(arg, match[2])) {
options.sourceMapURL = match[2];
}
break;
case 'source-map-output-map-file':
if (checkArgFunc(arg, match[2])) {
options.writeSourceMap = function(sourceMapContent) {
writeFile(match[2], sourceMapContent);
};
}
break;
case 'rp':
case 'rootpath':
if (checkArgFunc(arg, match[2])) {
options.rootpath = match[2].replace(/\\/g, '/');
}
break;
case "ru":
case "relative-urls":
options.relativeUrls = true;
break;
case "sm":
case "strict-math":
if (checkArgFunc(arg, match[2])) {
options.strictMath = checkBooleanArg(match[2]);
}
break;
case "su":
case "strict-units":
if (checkArgFunc(arg, match[2])) {
options.strictUnits = checkBooleanArg(match[2]);
}
break;
default:
console.log('invalid option ' + arg);
continueProcessing = false;
}
});
if (!continueProcessing) {
return;
}
var name = args[0];
if (name && name != '-') {
// name = path.resolve(process.cwd(), name);
}
var output = args[1];
var outputbase = args[1];
if (output) {
options.sourceMapOutputFilename = output;
// output = path.resolve(process.cwd(), output);
if (warningMessages) {
console.log(warningMessages);
}
}
// options.sourceMapBasepath = process.cwd();
// options.sourceMapBasepath = '';
if (options.sourceMap === true) {
console.log("output: " + output);
if (!output && !sourceMapFileInline) {
console.log("the sourcemap option only has an optional filename if the css filename is given");
return;
}
options.sourceMapFullFilename = options.sourceMapOutputFilename + ".map";
options.sourceMap = less.modules.path.basename(options.sourceMapFullFilename);
} else if (options.sourceMap) {
options.sourceMapOutputFilename = options.sourceMap;
}
if (!name) {
console.log("lessc: no inout files");
console.log("");
// TODO
// require('../lib/less/lessc_helper').printUsage();
currentErrorcode = 1;
return;
}
// var ensureDirectory = function (filepath) {
// var dir = path.dirname(filepath),
// cmd,
// existsSync = fs.existsSync || path.existsSync;
// if (!existsSync(dir)) {
// if (mkdirp === undefined) {
// try {mkdirp = require('mkdirp');}
// catch(e) { mkdirp = null; }
// }
// cmd = mkdirp && mkdirp.sync || fs.mkdirSync;
// cmd(dir);
// }
// };
if (options.depends) {
if (!outputbase) {
console.log("option --depends requires an output path to be specified");
return;
}
console.log(outputbase + ": ");
}
if (!name) {
console.log('No files present in the fileset');
quit(1);
}
var input = null;
try {
input = readFile(name, 'utf-8');
} catch (e) {
console.log('lesscss: couldn\'t open file ' + name);
quit(1);
}
options.filename = name;
var result;
try {
var parser = new less.Parser(options);
parser.parse(input, function (e, root) {
if (e) {
writeError(e, options);
quit(1);
} else {
result = root.toCSS(options);
if (output) {
writeFile(output, result);
console.log("Written to " + output);
} else {
print(result);
}
quit(0);
}
});
}
catch(e) {
writeError(e, options);
quit(1);
}
}(arguments));

View File

@ -0,0 +1,111 @@
var contexts = {};
module.exports = contexts;
var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {
if (!original) { return; }
for (var i = 0; i < propertiesToCopy.length; i++) {
if (original.hasOwnProperty(propertiesToCopy[i])) {
destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
}
}
};
/*
parse is used whilst parsing
*/
var parseCopyProperties = [
// options
'paths', // option - unmodified - paths to search for imports on
'relativeUrls', // option - whether to adjust URL's to be relative
'rootpath', // option - rootpath to append to URL's
'strictImports', // option -
'insecure', // option - whether to allow imports from insecure ssl hosts
'dumpLineNumbers', // option - whether to dump line numbers
'compress', // option - whether to compress
'syncImport', // option - whether to import synchronously
'chunkInput', // option - whether to chunk input. more performant but causes parse issues.
'mime', // browser only - mime type for sheet import
'useFileCache', // browser only - whether to use the per file session cache
// context
'processImports', // option & context - whether to process imports. if false then imports will not be imported.
// Used by the import manager to stop multiple import visitors being created.
'pluginManager' // Used as the plugin manager for the session
];
contexts.Parse = function(options) {
copyFromOriginal(options, this, parseCopyProperties);
if (typeof this.paths === "string") { this.paths = [this.paths]; }
};
var evalCopyProperties = [
'paths', // additional include paths
'compress', // whether to compress
'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
'strictMath', // whether math has to be within parenthesis
'strictUnits', // whether units need to evaluate correctly
'sourceMap', // whether to output a source map
'importMultiple', // whether we are currently importing multiple copies
'urlArgs', // whether to add args into url tokens
'javascriptEnabled',// option - whether JavaScript is enabled. if undefined, defaults to true
'pluginManager', // Used as the plugin manager for the session
'importantScope' // used to bubble up !important statements
];
contexts.Eval = function(options, frames) {
copyFromOriginal(options, this, evalCopyProperties);
if (typeof this.paths === "string") { this.paths = [this.paths]; }
this.frames = frames || [];
this.importantScope = this.importantScope || [];
};
contexts.Eval.prototype.inParenthesis = function () {
if (!this.parensStack) {
this.parensStack = [];
}
this.parensStack.push(true);
};
contexts.Eval.prototype.outOfParenthesis = function () {
this.parensStack.pop();
};
contexts.Eval.prototype.isMathOn = function () {
return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
};
contexts.Eval.prototype.isPathRelative = function (path) {
return !/^(?:[a-z-]+:|\/|#)/i.test(path);
};
contexts.Eval.prototype.normalizePath = function( path ) {
var
segments = path.split("/").reverse(),
segment;
path = [];
while (segments.length !== 0 ) {
segment = segments.pop();
switch( segment ) {
case ".":
break;
case "..":
if ((path.length === 0) || (path[path.length - 1] === "..")) {
path.push( segment );
} else {
path.pop();
}
break;
default:
path.push( segment );
break;
}
}
return path.join("/");
};
//todo - do the same for the toCSS ?

View File

@ -0,0 +1,150 @@
module.exports = {
'aliceblue':'#f0f8ff',
'antiquewhite':'#faebd7',
'aqua':'#00ffff',
'aquamarine':'#7fffd4',
'azure':'#f0ffff',
'beige':'#f5f5dc',
'bisque':'#ffe4c4',
'black':'#000000',
'blanchedalmond':'#ffebcd',
'blue':'#0000ff',
'blueviolet':'#8a2be2',
'brown':'#a52a2a',
'burlywood':'#deb887',
'cadetblue':'#5f9ea0',
'chartreuse':'#7fff00',
'chocolate':'#d2691e',
'coral':'#ff7f50',
'cornflowerblue':'#6495ed',
'cornsilk':'#fff8dc',
'crimson':'#dc143c',
'cyan':'#00ffff',
'darkblue':'#00008b',
'darkcyan':'#008b8b',
'darkgoldenrod':'#b8860b',
'darkgray':'#a9a9a9',
'darkgrey':'#a9a9a9',
'darkgreen':'#006400',
'darkkhaki':'#bdb76b',
'darkmagenta':'#8b008b',
'darkolivegreen':'#556b2f',
'darkorange':'#ff8c00',
'darkorchid':'#9932cc',
'darkred':'#8b0000',
'darksalmon':'#e9967a',
'darkseagreen':'#8fbc8f',
'darkslateblue':'#483d8b',
'darkslategray':'#2f4f4f',
'darkslategrey':'#2f4f4f',
'darkturquoise':'#00ced1',
'darkviolet':'#9400d3',
'deeppink':'#ff1493',
'deepskyblue':'#00bfff',
'dimgray':'#696969',
'dimgrey':'#696969',
'dodgerblue':'#1e90ff',
'firebrick':'#b22222',
'floralwhite':'#fffaf0',
'forestgreen':'#228b22',
'fuchsia':'#ff00ff',
'gainsboro':'#dcdcdc',
'ghostwhite':'#f8f8ff',
'gold':'#ffd700',
'goldenrod':'#daa520',
'gray':'#808080',
'grey':'#808080',
'green':'#008000',
'greenyellow':'#adff2f',
'honeydew':'#f0fff0',
'hotpink':'#ff69b4',
'indianred':'#cd5c5c',
'indigo':'#4b0082',
'ivory':'#fffff0',
'khaki':'#f0e68c',
'lavender':'#e6e6fa',
'lavenderblush':'#fff0f5',
'lawngreen':'#7cfc00',
'lemonchiffon':'#fffacd',
'lightblue':'#add8e6',
'lightcoral':'#f08080',
'lightcyan':'#e0ffff',
'lightgoldenrodyellow':'#fafad2',
'lightgray':'#d3d3d3',
'lightgrey':'#d3d3d3',
'lightgreen':'#90ee90',
'lightpink':'#ffb6c1',
'lightsalmon':'#ffa07a',
'lightseagreen':'#20b2aa',
'lightskyblue':'#87cefa',
'lightslategray':'#778899',
'lightslategrey':'#778899',
'lightsteelblue':'#b0c4de',
'lightyellow':'#ffffe0',
'lime':'#00ff00',
'limegreen':'#32cd32',
'linen':'#faf0e6',
'magenta':'#ff00ff',
'maroon':'#800000',
'mediumaquamarine':'#66cdaa',
'mediumblue':'#0000cd',
'mediumorchid':'#ba55d3',
'mediumpurple':'#9370d8',
'mediumseagreen':'#3cb371',
'mediumslateblue':'#7b68ee',
'mediumspringgreen':'#00fa9a',
'mediumturquoise':'#48d1cc',
'mediumvioletred':'#c71585',
'midnightblue':'#191970',
'mintcream':'#f5fffa',
'mistyrose':'#ffe4e1',
'moccasin':'#ffe4b5',
'navajowhite':'#ffdead',
'navy':'#000080',
'oldlace':'#fdf5e6',
'olive':'#808000',
'olivedrab':'#6b8e23',
'orange':'#ffa500',
'orangered':'#ff4500',
'orchid':'#da70d6',
'palegoldenrod':'#eee8aa',
'palegreen':'#98fb98',
'paleturquoise':'#afeeee',
'palevioletred':'#d87093',
'papayawhip':'#ffefd5',
'peachpuff':'#ffdab9',
'peru':'#cd853f',
'pink':'#ffc0cb',
'plum':'#dda0dd',
'powderblue':'#b0e0e6',
'purple':'#800080',
'rebeccapurple':'#663399',
'red':'#ff0000',
'rosybrown':'#bc8f8f',
'royalblue':'#4169e1',
'saddlebrown':'#8b4513',
'salmon':'#fa8072',
'sandybrown':'#f4a460',
'seagreen':'#2e8b57',
'seashell':'#fff5ee',
'sienna':'#a0522d',
'silver':'#c0c0c0',
'skyblue':'#87ceeb',
'slateblue':'#6a5acd',
'slategray':'#708090',
'slategrey':'#708090',
'snow':'#fffafa',
'springgreen':'#00ff7f',
'steelblue':'#4682b4',
'tan':'#d2b48c',
'teal':'#008080',
'thistle':'#d8bfd8',
'tomato':'#ff6347',
'turquoise':'#40e0d0',
'violet':'#ee82ee',
'wheat':'#f5deb3',
'white':'#ffffff',
'whitesmoke':'#f5f5f5',
'yellow':'#ffff00',
'yellowgreen':'#9acd32'
};

View File

@ -0,0 +1,4 @@
module.exports = {
colors: require("./colors"),
unitConversions: require("./unit-conversions")
};

View File

@ -0,0 +1,21 @@
module.exports = {
length: {
'm': 1,
'cm': 0.01,
'mm': 0.001,
'in': 0.0254,
'px': 0.0254 / 96,
'pt': 0.0254 / 72,
'pc': 0.0254 / 72 * 12
},
duration: {
's': 1,
'ms': 0.001
},
angle: {
'rad': 1 / (2 * Math.PI),
'deg': 1 / 360,
'grad': 1 / 400,
'turn': 1
}
};

View File

@ -0,0 +1,123 @@
var abstractFileManager = function() {
};
abstractFileManager.prototype.getPath = function (filename) {
var j = filename.lastIndexOf('?');
if (j > 0) {
filename = filename.slice(0, j);
}
j = filename.lastIndexOf('/');
if (j < 0) {
j = filename.lastIndexOf('\\');
}
if (j < 0) {
return "";
}
return filename.slice(0, j + 1);
};
abstractFileManager.prototype.tryAppendExtension = function(path, ext) {
return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext;
};
abstractFileManager.prototype.tryAppendLessExtension = function(path) {
return this.tryAppendExtension(path, '.less');
};
abstractFileManager.prototype.supportsSync = function() {
return false;
};
abstractFileManager.prototype.alwaysMakePathsAbsolute = function() {
return false;
};
abstractFileManager.prototype.isPathAbsolute = function(filename) {
return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename);
};
abstractFileManager.prototype.join = function(basePath, laterPath) {
if (!basePath) {
return laterPath;
}
return basePath + laterPath;
};
abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) {
// diff between two paths to create a relative path
var urlParts = this.extractUrlParts(url),
baseUrlParts = this.extractUrlParts(baseUrl),
i, max, urlDirectories, baseUrlDirectories, diff = "";
if (urlParts.hostPart !== baseUrlParts.hostPart) {
return "";
}
max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
for (i = 0; i < max; i++) {
if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
}
baseUrlDirectories = baseUrlParts.directories.slice(i);
urlDirectories = urlParts.directories.slice(i);
for (i = 0; i < baseUrlDirectories.length - 1; i++) {
diff += "../";
}
for (i = 0; i < urlDirectories.length - 1; i++) {
diff += urlDirectories[i] + "/";
}
return diff;
};
// helper function, not part of API
abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) {
// urlParts[1] = protocol://hostname/ OR /
// urlParts[2] = / if path relative to host base
// urlParts[3] = directories
// urlParts[4] = filename
// urlParts[5] = parameters
var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
urlParts = url.match(urlPartsRegex),
returner = {}, directories = [], i, baseUrlParts;
if (!urlParts) {
throw new Error("Could not parse sheet href - '" + url + "'");
}
// Stylesheets in IE don't always return the full path
if (baseUrl && (!urlParts[1] || urlParts[2])) {
baseUrlParts = baseUrl.match(urlPartsRegex);
if (!baseUrlParts) {
throw new Error("Could not parse page url - '" + baseUrl + "'");
}
urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
if (!urlParts[2]) {
urlParts[3] = baseUrlParts[3] + urlParts[3];
}
}
if (urlParts[3]) {
directories = urlParts[3].replace(/\\/g, "/").split("/");
// extract out . before .. so .. doesn't absorb a non-directory
for (i = 0; i < directories.length; i++) {
if (directories[i] === ".") {
directories.splice(i, 1);
i -= 1;
}
}
for (i = 0; i < directories.length; i++) {
if (directories[i] === ".." && i > 0) {
directories.splice(i - 1, 2);
i -= 2;
}
}
}
returner.hostPart = urlParts[1];
returner.directories = directories;
returner.path = (urlParts[1] || "") + directories.join("/");
returner.fileUrl = returner.path + (urlParts[4] || "");
returner.url = returner.fileUrl + (urlParts[5] || "");
return returner;
};
module.exports = abstractFileManager;

View File

@ -0,0 +1,25 @@
module.exports = {
/**
* Converts a string to a base 64 string
* @param str
*/
encodeBase64: function(str) {
},
/**
* Lookup the mime-type of a filename
* @param filename
*/
mimeLookup: function (filename) {
},
/**
* Look up the charset of a mime type
* @param mime
*/
charsetLookup: function (mime) {
},
/**
* Gets a source map generator
*/
getSourceMapGenerator: function getSourceMapGenerator() {
}
};

View File

@ -0,0 +1,51 @@
var logger = require("../logger");
var environment = function(externalEnvironment, fileManagers) {
this.fileManagers = fileManagers || [];
externalEnvironment = externalEnvironment || {};
var optionalFunctions = ["encodeBase64", "mimeLookup", "charsetLookup", "getSourceMapGenerator"],
requiredFunctions = [],
functions = requiredFunctions.concat(optionalFunctions);
for (var i = 0; i < functions.length; i++) {
var propName = functions[i],
environmentFunc = externalEnvironment[propName];
if (environmentFunc) {
this[propName] = environmentFunc.bind(externalEnvironment);
} else if (i < requiredFunctions.length) {
this.warn("missing required function in environment - " + propName);
}
}
};
environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) {
if (!filename) {
logger.warn("getFileManager called with no filename.. Please report this issue. continuing.");
}
if (currentDirectory == null) {
logger.warn("getFileManager called with null directory.. Please report this issue. continuing.");
}
var fileManagers = this.fileManagers;
if (options.pluginManager) {
fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers());
}
for (var i = fileManagers.length - 1; i >= 0 ; i--) {
var fileManager = fileManagers[i];
if (fileManager[isSync ? "supportsSync" : "supports"](filename, currentDirectory, options, environment)) {
return fileManager;
}
}
return null;
};
environment.prototype.addFileManager = function (fileManager) {
this.fileManagers.push(fileManager);
};
environment.prototype.clearFileManagers = function () {
this.fileManagers = [];
};
module.exports = environment;

View File

@ -0,0 +1,103 @@
module.exports = {
/**
* Given the full path to a file, return the path component
* Provided by AbstractFileManager
* @param {string} filename
* @returns {string}
*/
getPath: function(filename) {
},
/**
* Append a .less extension if appropriate. Only called if less thinks one could be added.
* Provided by AbstractFileManager
* @param filename
* @returns {string}
*/
tryAppendLessExtension: function(filename) {
},
/**
* Whether the rootpath should be converted to be absolute.
* The browser ovverides this to return true because urls must be absolute.
* Provided by AbstractFileManager (returns false)
* @returns {bool}
*/
alwaysMakePathsAbsolute: function() {
},
/**
* Returns whether a path is absolute
* Provided by AbstractFileManager
* @param {string} path
* @returns {bool}
*/
isPathAbsolute: function(path) {
},
/**
* joins together 2 paths
* Provided by AbstractFileManager
* @param {string} basePath
* @param {string} laterPath
*/
join: function(basePath, laterPath) {
},
/**
* Returns the difference between 2 paths
* E.g. url = a/ baseUrl = a/b/ returns ../
* url = a/b/ baseUrl = a/ returns b/
* Provided by AbstractFileManager
* @param {string} url
* @param {string} baseUrl
* @returns {string}
*/
pathDiff: function(url, baseUrl) {
},
/**
* Returns whether this file manager supports this file for syncronous file retrieval
* If true is returned, loadFileSync will then be called with the file.
* Provided by AbstractFileManager (returns false)
* @param {string} filename
* @param {string} currentDirectory
* @param {object} options
* @param {less.environment.environment} environment
* @returns {bool}
*/
supportsSync: function(filename, currentDirectory, options, environment) {
},
/**
*
* @param {string} filename
* @param {string} currentDirectory
* @param {object} options
* @param {less.environment.environment} environment
* @returns {bool}
*/
supports: function(filename, currentDirectory, options, environment) {
},
/**
* Loads a file asynchronously. Expects a promise that either rejects with an error or fulfills with an
* object containing
* { filename: - full resolved path to file
* contents: - the contents of the file, as a string }
*
* @param {string} filename
* @param {string} currentDirectory
* @param {object} options
* @param {less.environment.environment} environment
* @returns {Promise}
*/
loadFile: function(filename, currentDirectory, options, environment) {
},
/**
* Loads a file synchronously. Expects an immediate return with an object containing
* { error: - error object if an error occurs
* filename: - full resolved path to file
* contents: - the contents of the file, as a string }
*
* @param {string} filename
* @param {string} currentDirectory
* @param {object} options
* @param {less.environment.environment} environment
* @returns {object} should be an object containing error or contents and filename
*/
loadFileSync: function(filename, currentDirectory, options, environment) {
}
};

View File

@ -0,0 +1,74 @@
var Color = require("../tree/color"),
functionRegistry = require("./function-registry");
// Color Blending
// ref: http://www.w3.org/TR/compositing-1
function colorBlend(mode, color1, color2) {
var ab = color1.alpha, cb, // backdrop
as = color2.alpha, cs, // source
ar, cr, r = []; // result
ar = as + ab * (1 - as);
for (var i = 0; i < 3; i++) {
cb = color1.rgb[i] / 255;
cs = color2.rgb[i] / 255;
cr = mode(cb, cs);
if (ar) {
cr = (as * cs + ab * (cb -
as * (cb + cs - cr))) / ar;
}
r[i] = cr * 255;
}
return new Color(r, ar);
}
var colorBlendModeFunctions = {
multiply: function(cb, cs) {
return cb * cs;
},
screen: function(cb, cs) {
return cb + cs - cb * cs;
},
overlay: function(cb, cs) {
cb *= 2;
return (cb <= 1) ?
colorBlendModeFunctions.multiply(cb, cs) :
colorBlendModeFunctions.screen(cb - 1, cs);
},
softlight: function(cb, cs) {
var d = 1, e = cb;
if (cs > 0.5) {
e = 1;
d = (cb > 0.25) ? Math.sqrt(cb)
: ((16 * cb - 12) * cb + 4) * cb;
}
return cb - (1 - 2 * cs) * e * (d - cb);
},
hardlight: function(cb, cs) {
return colorBlendModeFunctions.overlay(cs, cb);
},
difference: function(cb, cs) {
return Math.abs(cb - cs);
},
exclusion: function(cb, cs) {
return cb + cs - 2 * cb * cs;
},
// non-w3c functions:
average: function(cb, cs) {
return (cb + cs) / 2;
},
negation: function(cb, cs) {
return 1 - Math.abs(cb + cs - 1);
}
};
for (var f in colorBlendModeFunctions) {
if (colorBlendModeFunctions.hasOwnProperty(f)) {
colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]);
}
}
functionRegistry.addMultiple(colorBlend);

View File

@ -0,0 +1,322 @@
var Dimension = require("../tree/dimension"),
Color = require("../tree/color"),
Quoted = require("../tree/quoted"),
Anonymous = require("../tree/anonymous"),
functionRegistry = require("./function-registry"),
colorFunctions;
function clamp(val) {
return Math.min(1, Math.max(0, val));
}
function hsla(color) {
return colorFunctions.hsla(color.h, color.s, color.l, color.a);
}
function number(n) {
if (n instanceof Dimension) {
return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
} else if (typeof n === 'number') {
return n;
} else {
throw {
type: "Argument",
message: "color functions take numbers as parameters"
};
}
}
function scaled(n, size) {
if (n instanceof Dimension && n.unit.is('%')) {
return parseFloat(n.value * size / 100);
} else {
return number(n);
}
}
colorFunctions = {
rgb: function (r, g, b) {
return colorFunctions.rgba(r, g, b, 1.0);
},
rgba: function (r, g, b, a) {
var rgb = [r, g, b].map(function (c) { return scaled(c, 255); });
a = number(a);
return new Color(rgb, a);
},
hsl: function (h, s, l) {
return colorFunctions.hsla(h, s, l, 1.0);
},
hsla: function (h, s, l, a) {
var m1, m2;
function hue(h) {
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
if (h * 6 < 1) {
return m1 + (m2 - m1) * h * 6;
}
else if (h * 2 < 1) {
return m2;
}
else if (h * 3 < 2) {
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
}
else {
return m1;
}
}
h = (number(h) % 360) / 360;
s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
m1 = l * 2 - m2;
return colorFunctions.rgba(hue(h + 1 / 3) * 255,
hue(h) * 255,
hue(h - 1 / 3) * 255,
a);
},
hsv: function(h, s, v) {
return colorFunctions.hsva(h, s, v, 1.0);
},
hsva: function(h, s, v, a) {
h = ((number(h) % 360) / 360) * 360;
s = number(s); v = number(v); a = number(a);
var i, f;
i = Math.floor((h / 60) % 6);
f = (h / 60) - i;
var vs = [v,
v * (1 - s),
v * (1 - f * s),
v * (1 - (1 - f) * s)];
var perm = [[0, 3, 1],
[2, 0, 1],
[1, 0, 3],
[1, 2, 0],
[3, 1, 0],
[0, 1, 2]];
return colorFunctions.rgba(vs[perm[i][0]] * 255,
vs[perm[i][1]] * 255,
vs[perm[i][2]] * 255,
a);
},
hue: function (color) {
return new Dimension(color.toHSL().h);
},
saturation: function (color) {
return new Dimension(color.toHSL().s * 100, '%');
},
lightness: function (color) {
return new Dimension(color.toHSL().l * 100, '%');
},
hsvhue: function(color) {
return new Dimension(color.toHSV().h);
},
hsvsaturation: function (color) {
return new Dimension(color.toHSV().s * 100, '%');
},
hsvvalue: function (color) {
return new Dimension(color.toHSV().v * 100, '%');
},
red: function (color) {
return new Dimension(color.rgb[0]);
},
green: function (color) {
return new Dimension(color.rgb[1]);
},
blue: function (color) {
return new Dimension(color.rgb[2]);
},
alpha: function (color) {
return new Dimension(color.toHSL().a);
},
luma: function (color) {
return new Dimension(color.luma() * color.alpha * 100, '%');
},
luminance: function (color) {
var luminance =
(0.2126 * color.rgb[0] / 255) +
(0.7152 * color.rgb[1] / 255) +
(0.0722 * color.rgb[2] / 255);
return new Dimension(luminance * color.alpha * 100, '%');
},
saturate: function (color, amount, method) {
// filter: saturate(3.2);
// should be kept as is, so check for color
if (!color.rgb) {
return null;
}
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.s += hsl.s * amount.value / 100;
}
else {
hsl.s += amount.value / 100;
}
hsl.s = clamp(hsl.s);
return hsla(hsl);
},
desaturate: function (color, amount, method) {
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.s -= hsl.s * amount.value / 100;
}
else {
hsl.s -= amount.value / 100;
}
hsl.s = clamp(hsl.s);
return hsla(hsl);
},
lighten: function (color, amount, method) {
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.l += hsl.l * amount.value / 100;
}
else {
hsl.l += amount.value / 100;
}
hsl.l = clamp(hsl.l);
return hsla(hsl);
},
darken: function (color, amount, method) {
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.l -= hsl.l * amount.value / 100;
}
else {
hsl.l -= amount.value / 100;
}
hsl.l = clamp(hsl.l);
return hsla(hsl);
},
fadein: function (color, amount, method) {
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.a += hsl.a * amount.value / 100;
}
else {
hsl.a += amount.value / 100;
}
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
fadeout: function (color, amount, method) {
var hsl = color.toHSL();
if (typeof method !== "undefined" && method.value === "relative") {
hsl.a -= hsl.a * amount.value / 100;
}
else {
hsl.a -= amount.value / 100;
}
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
fade: function (color, amount) {
var hsl = color.toHSL();
hsl.a = amount.value / 100;
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
spin: function (color, amount) {
var hsl = color.toHSL();
var hue = (hsl.h + amount.value) % 360;
hsl.h = hue < 0 ? 360 + hue : hue;
return hsla(hsl);
},
//
// Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein
// http://sass-lang.com
//
mix: function (color1, color2, weight) {
if (!color1.toHSL || !color2.toHSL) {
console.log(color2.type);
console.dir(color2);
}
if (!weight) {
weight = new Dimension(50);
}
var p = weight.value / 100.0;
var w = p * 2 - 1;
var a = color1.toHSL().a - color2.toHSL().a;
var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
var w2 = 1 - w1;
var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
color1.rgb[1] * w1 + color2.rgb[1] * w2,
color1.rgb[2] * w1 + color2.rgb[2] * w2];
var alpha = color1.alpha * p + color2.alpha * (1 - p);
return new Color(rgb, alpha);
},
greyscale: function (color) {
return colorFunctions.desaturate(color, new Dimension(100));
},
contrast: function (color, dark, light, threshold) {
// filter: contrast(3.2);
// should be kept as is, so check for color
if (!color.rgb) {
return null;
}
if (typeof light === 'undefined') {
light = colorFunctions.rgba(255, 255, 255, 1.0);
}
if (typeof dark === 'undefined') {
dark = colorFunctions.rgba(0, 0, 0, 1.0);
}
//Figure out which is actually light and dark!
if (dark.luma() > light.luma()) {
var t = light;
light = dark;
dark = t;
}
if (typeof threshold === 'undefined') {
threshold = 0.43;
} else {
threshold = number(threshold);
}
if (color.luma() < threshold) {
return light;
} else {
return dark;
}
},
argb: function (color) {
return new Anonymous(color.toARGB());
},
color: function(c) {
if ((c instanceof Quoted) &&
(/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) {
return new Color(c.value.slice(1));
}
if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) {
c.value = undefined;
return c;
}
throw {
type: "Argument",
message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF"
};
},
tint: function(color, amount) {
return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount);
},
shade: function(color, amount) {
return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount);
}
};
functionRegistry.addMultiple(colorFunctions);

View File

@ -0,0 +1,85 @@
module.exports = function(environment) {
var Quoted = require("../tree/quoted"),
URL = require("../tree/url"),
functionRegistry = require("./function-registry"),
fallback = function(functionThis, node) {
return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context);
},
logger = require('../logger');
functionRegistry.add("data-uri", function(mimetypeNode, filePathNode) {
if (!filePathNode) {
filePathNode = mimetypeNode;
mimetypeNode = null;
}
var mimetype = mimetypeNode && mimetypeNode.value;
var filePath = filePathNode.value;
var currentFileInfo = this.currentFileInfo;
var currentDirectory = currentFileInfo.relativeUrls ?
currentFileInfo.currentDirectory : currentFileInfo.entryPath;
var fragmentStart = filePath.indexOf('#');
var fragment = '';
if (fragmentStart !== -1) {
fragment = filePath.slice(fragmentStart);
filePath = filePath.slice(0, fragmentStart);
}
var fileManager = environment.getFileManager(filePath, currentDirectory, this.context, environment, true);
if (!fileManager) {
return fallback(this, filePathNode);
}
var useBase64 = false;
// detect the mimetype if not given
if (!mimetypeNode) {
mimetype = environment.mimeLookup(filePath);
if (mimetype === "image/svg+xml") {
useBase64 = false;
} else {
// use base 64 unless it's an ASCII or UTF-8 format
var charset = environment.charsetLookup(mimetype);
useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
}
if (useBase64) { mimetype += ';base64'; }
}
else {
useBase64 = /;base64$/.test(mimetype);
}
var fileSync = fileManager.loadFileSync(filePath, currentDirectory, this.context, environment);
if (!fileSync.contents) {
logger.warn("Skipped data-uri embedding of " + filePath + " because file not found");
return fallback(this, filePathNode || mimetypeNode);
}
var buf = fileSync.contents;
if (useBase64 && !environment.encodeBase64) {
return fallback(this, filePathNode);
}
buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);
var uri = "data:" + mimetype + ',' + buf + fragment;
// IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
// and the --ieCompat flag is enabled, return a normal url() instead.
var DATA_URI_MAX = 32768;
if (uri.length >= DATA_URI_MAX) {
if (this.context.ieCompat !== false) {
logger.warn("Skipped data-uri embedding of " + filePath + " because its size (" + uri.length +
" characters) exceeds IE8-safe " + DATA_URI_MAX + " characters!");
return fallback(this, filePathNode || mimetypeNode);
}
}
return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
});
};

View File

@ -0,0 +1,27 @@
var Keyword = require("../tree/keyword"),
functionRegistry = require("./function-registry");
var defaultFunc = {
eval: function () {
var v = this.value_, e = this.error_;
if (e) {
throw e;
}
if (v != null) {
return v ? Keyword.True : Keyword.False;
}
},
value: function (v) {
this.value_ = v;
},
error: function (e) {
this.error_ = e;
},
reset: function () {
this.value_ = this.error_ = null;
}
};
functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc));
module.exports = defaultFunc;

View File

@ -0,0 +1,46 @@
var Expression = require("../tree/expression");
var functionCaller = function(name, context, index, currentFileInfo) {
this.name = name.toLowerCase();
this.index = index;
this.context = context;
this.currentFileInfo = currentFileInfo;
this.func = context.frames[0].functionRegistry.get(this.name);
};
functionCaller.prototype.isValid = function() {
return Boolean(this.func);
};
functionCaller.prototype.call = function(args) {
// This code is terrible and should be replaced as per this issue...
// https://github.com/less/less.js/issues/2477
if (Array.isArray(args)) {
args = args.filter(function (item) {
if (item.type === "Comment") {
return false;
}
return true;
})
.map(function(item) {
if (item.type === "Expression") {
var subNodes = item.value.filter(function (item) {
if (item.type === "Comment") {
return false;
}
return true;
});
if (subNodes.length === 1) {
return subNodes[0];
} else {
return new Expression(subNodes);
}
}
return item;
});
}
return this.func.apply(this, args);
};
module.exports = functionCaller;

View File

@ -0,0 +1,29 @@
function makeRegistry( base ) {
return {
_data: {},
add: function(name, func) {
// precautionary case conversion, as later querying of
// the registry by function-caller uses lower case as well.
name = name.toLowerCase();
if (this._data.hasOwnProperty(name)) {
//TODO warn
}
this._data[name] = func;
},
addMultiple: function(functions) {
Object.keys(functions).forEach(
function(name) {
this.add(name, functions[name]);
}.bind(this));
},
get: function(name) {
return this._data[name] || ( base && base.get( name ));
},
inherit : function() {
return makeRegistry( this );
}
};
}
module.exports = makeRegistry( null );

View File

@ -0,0 +1,19 @@
module.exports = function(environment) {
var functions = {
functionRegistry: require("./function-registry"),
functionCaller: require("./function-caller")
};
//register functions
require("./default");
require("./color");
require("./color-blending");
require("./data-uri")(environment);
require("./math");
require("./number");
require("./string");
require("./svg")(environment);
require("./types");
return functions;
};

View File

@ -0,0 +1,16 @@
var Dimension = require("../tree/dimension");
var MathHelper = function() {
};
MathHelper._math = function (fn, unit, n) {
if (!(n instanceof Dimension)) {
throw { type: "Argument", message: "argument must be a number" };
}
if (unit == null) {
unit = n.unit;
} else {
n = n.unify();
}
return new Dimension(fn(parseFloat(n.value)), unit);
};
module.exports = MathHelper;

View File

@ -0,0 +1,29 @@
var functionRegistry = require("./function-registry"),
mathHelper = require("./math-helper.js");
var mathFunctions = {
// name, unit
ceil: null,
floor: null,
sqrt: null,
abs: null,
tan: "",
sin: "",
cos: "",
atan: "rad",
asin: "rad",
acos: "rad"
};
for (var f in mathFunctions) {
if (mathFunctions.hasOwnProperty(f)) {
mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]);
}
}
mathFunctions.round = function (n, f) {
var fraction = typeof f === "undefined" ? 0 : f.value;
return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n);
};
functionRegistry.addMultiple(mathFunctions);

View File

@ -0,0 +1,81 @@
var Dimension = require("../tree/dimension"),
Anonymous = require("../tree/anonymous"),
functionRegistry = require("./function-registry"),
mathHelper = require("./math-helper.js");
var minMax = function (isMin, args) {
args = Array.prototype.slice.call(args);
switch(args.length) {
case 0: throw { type: "Argument", message: "one or more arguments required" };
}
var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone,
order = [], // elems only contains original argument values.
values = {}; // key is the unit.toString() for unified Dimension values,
// value is the index into the order array.
for (i = 0; i < args.length; i++) {
current = args[i];
if (!(current instanceof Dimension)) {
if (Array.isArray(args[i].value)) {
Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value));
}
continue;
}
currentUnified = current.unit.toString() === "" && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify();
unit = currentUnified.unit.toString() === "" && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString();
unitStatic = unit !== "" && unitStatic === undefined || unit !== "" && order[0].unify().unit.toString() === "" ? unit : unitStatic;
unitClone = unit !== "" && unitClone === undefined ? current.unit.toString() : unitClone;
j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit];
if (j === undefined) {
if (unitStatic !== undefined && unit !== unitStatic) {
throw{ type: "Argument", message: "incompatible types" };
}
values[unit] = order.length;
order.push(current);
continue;
}
referenceUnified = order[j].unit.toString() === "" && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify();
if ( isMin && currentUnified.value < referenceUnified.value ||
!isMin && currentUnified.value > referenceUnified.value) {
order[j] = current;
}
}
if (order.length == 1) {
return order[0];
}
args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? "," : ", ");
return new Anonymous((isMin ? "min" : "max") + "(" + args + ")");
};
functionRegistry.addMultiple({
min: function () {
return minMax(true, arguments);
},
max: function () {
return minMax(false, arguments);
},
convert: function (val, unit) {
return val.convertTo(unit.value);
},
pi: function () {
return new Dimension(Math.PI);
},
mod: function(a, b) {
return new Dimension(a.value % b.value, a.unit);
},
pow: function(x, y) {
if (typeof x === "number" && typeof y === "number") {
x = new Dimension(x);
y = new Dimension(y);
} else if (!(x instanceof Dimension) || !(y instanceof Dimension)) {
throw { type: "Argument", message: "arguments must be numbers" };
}
return new Dimension(Math.pow(x.value, y.value), x.unit);
},
percentage: function (n) {
var result = mathHelper._math(function(num) {
return num * 100;
}, '%', n);
return result;
}
});

View File

@ -0,0 +1,37 @@
var Quoted = require("../tree/quoted"),
Anonymous = require("../tree/anonymous"),
JavaScript = require("../tree/javascript"),
functionRegistry = require("./function-registry");
functionRegistry.addMultiple({
e: function (str) {
return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value);
},
escape: function (str) {
return new Anonymous(
encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B")
.replace(/\(/g, "%28").replace(/\)/g, "%29"));
},
replace: function (string, pattern, replacement, flags) {
var result = string.value;
replacement = (replacement.type === "Quoted") ?
replacement.value : replacement.toCSS();
result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);
return new Quoted(string.quote || '', result, string.escaped);
},
'%': function (string /* arg, arg, ...*/) {
var args = Array.prototype.slice.call(arguments, 1),
result = string.value;
for (var i = 0; i < args.length; i++) {
/*jshint loopfunc:true */
result = result.replace(/%[sda]/i, function(token) {
var value = ((args[i].type === "Quoted") &&
token.match(/s/i)) ? args[i].value : args[i].toCSS();
return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
});
}
result = result.replace(/%%/g, '%');
return new Quoted(string.quote || '', result, string.escaped);
}
});

View File

@ -0,0 +1,88 @@
module.exports = function(environment) {
var Dimension = require("../tree/dimension"),
Color = require("../tree/color"),
Expression = require("../tree/expression"),
Quoted = require("../tree/quoted"),
URL = require("../tree/url"),
functionRegistry = require("./function-registry");
functionRegistry.add("svg-gradient", function(direction) {
var stops,
gradientDirectionSvg,
gradientType = "linear",
rectangleDimension = 'x="0" y="0" width="1" height="1"',
renderEnv = {compress: false},
returner,
directionValue = direction.toCSS(renderEnv),
i, color, position, positionValue, alpha;
function throwArgumentDescriptor() {
throw { type: "Argument",
message: "svg-gradient expects direction, start_color [start_position], [color position,]...," +
" end_color [end_position] or direction, color list" };
}
if (arguments.length == 2) {
if (arguments[1].value.length < 2) {
throwArgumentDescriptor();
}
stops = arguments[1].value;
} else if (arguments.length < 3) {
throwArgumentDescriptor();
} else {
stops = Array.prototype.slice.call(arguments, 1);
}
switch (directionValue) {
case "to bottom":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
break;
case "to right":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
break;
case "to bottom right":
gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
break;
case "to top right":
gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
break;
case "ellipse":
case "ellipse at center":
gradientType = "radial";
gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
break;
default:
throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right'," +
" 'to bottom right', 'to top right' or 'ellipse at center'" };
}
returner = '<?xml version="1.0" ?>' +
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
'<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
for (i = 0; i < stops.length; i+= 1) {
if (stops[i] instanceof Expression) {
color = stops[i].value[0];
position = stops[i].value[1];
} else {
color = stops[i];
position = undefined;
}
if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
throwArgumentDescriptor();
}
positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
alpha = color.alpha;
returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
}
returner += '</' + gradientType + 'Gradient>' +
'<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
returner = encodeURIComponent(returner);
returner = "data:image/svg+xml," + returner;
return new URL(new Quoted("'" + returner + "'", returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
});
};

View File

@ -0,0 +1,89 @@
var Keyword = require("../tree/keyword"),
DetachedRuleset = require("../tree/detached-ruleset"),
Dimension = require("../tree/dimension"),
Color = require("../tree/color"),
Quoted = require("../tree/quoted"),
Anonymous = require("../tree/anonymous"),
URL = require("../tree/url"),
Operation = require("../tree/operation"),
functionRegistry = require("./function-registry");
var isa = function (n, Type) {
return (n instanceof Type) ? Keyword.True : Keyword.False;
},
isunit = function (n, unit) {
if (unit === undefined) {
throw { type: "Argument", message: "missing the required second argument to isunit." };
}
unit = typeof unit.value === "string" ? unit.value : unit;
if (typeof unit !== "string") {
throw { type: "Argument", message: "Second argument to isunit should be a unit or a string." };
}
return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;
},
getItemsFromNode = function(node) {
// handle non-array values as an array of length 1
// return 'undefined' if index is invalid
var items = Array.isArray(node.value) ?
node.value : Array(node);
return items;
};
functionRegistry.addMultiple({
isruleset: function (n) {
return isa(n, DetachedRuleset);
},
iscolor: function (n) {
return isa(n, Color);
},
isnumber: function (n) {
return isa(n, Dimension);
},
isstring: function (n) {
return isa(n, Quoted);
},
iskeyword: function (n) {
return isa(n, Keyword);
},
isurl: function (n) {
return isa(n, URL);
},
ispixel: function (n) {
return isunit(n, 'px');
},
ispercentage: function (n) {
return isunit(n, '%');
},
isem: function (n) {
return isunit(n, 'em');
},
isunit: isunit,
unit: function (val, unit) {
if (!(val instanceof Dimension)) {
throw { type: "Argument",
message: "the first argument to unit must be a number" +
(val instanceof Operation ? ". Have you forgotten parenthesis?" : "") };
}
if (unit) {
if (unit instanceof Keyword) {
unit = unit.value;
} else {
unit = unit.toCSS();
}
} else {
unit = "";
}
return new Dimension(val.value, unit);
},
"get-unit": function (n) {
return new Anonymous(n.unit);
},
extract: function(values, index) {
index = index.value - 1; // (1-based index)
return getItemsFromNode(values)[index];
},
length: function(values) {
return new Dimension(getItemsFromNode(values).length);
}
});

View File

@ -0,0 +1,131 @@
var contexts = require("./contexts"),
Parser = require('./parser/parser'),
FunctionImporter = require('./plugins/function-importer');
module.exports = function(environment) {
// FileInfo = {
// 'relativeUrls' - option - whether to adjust URL's to be relative
// 'filename' - full resolved filename of current file
// 'rootpath' - path to append to normal URLs for this node
// 'currentDirectory' - path to the current file, absolute
// 'rootFilename' - filename of the base file
// 'entryPath' - absolute path to the entry file
// 'reference' - whether the file should not be output and only output parts that are referenced
var ImportManager = function(context, rootFileInfo) {
this.rootFilename = rootFileInfo.filename;
this.paths = context.paths || []; // Search paths, when importing
this.contents = {}; // map - filename to contents of all the files
this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore
this.mime = context.mime;
this.error = null;
this.context = context;
// Deprecated? Unused outside of here, could be useful.
this.queue = []; // Files which haven't been imported yet
this.files = {}; // Holds the imported parse trees.
};
/**
* Add an import to be imported
* @param path - the raw path
* @param tryAppendLessExtension - whether to try appending the less extension (if the path has no extension)
* @param currentFileInfo - the current file info (used for instance to work out relative paths)
* @param importOptions - import options
* @param callback - callback for when it is imported
*/
ImportManager.prototype.push = function (path, tryAppendLessExtension, currentFileInfo, importOptions, callback) {
var importManager = this;
this.queue.push(path);
var fileParsedFunc = function (e, root, fullPath) {
importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue
var importedEqualsRoot = fullPath === importManager.rootFilename;
if (importOptions.optional && e) {
callback(null, {rules:[]}, false, null);
}
else {
importManager.files[fullPath] = root;
if (e && !importManager.error) { importManager.error = e; }
callback(e, root, importedEqualsRoot, fullPath);
}
};
var newFileInfo = {
relativeUrls: this.context.relativeUrls,
entryPath: currentFileInfo.entryPath,
rootpath: currentFileInfo.rootpath,
rootFilename: currentFileInfo.rootFilename
};
var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment);
if (!fileManager) {
fileParsedFunc({ message: "Could not find a file-manager for " + path });
return;
}
if (tryAppendLessExtension) {
path = fileManager.tryAppendExtension(path, importOptions.plugin ? ".js" : ".less");
}
var loadFileCallback = function(loadedFile) {
var resolvedFilename = loadedFile.filename,
contents = loadedFile.contents.replace(/^\uFEFF/, '');
// Pass on an updated rootpath if path of imported file is relative and file
// is in a (sub|sup) directory
//
// Examples:
// - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
// then rootpath should become 'less/module/nav/'
// - If path of imported file is '../mixins.less' and rootpath is 'less/',
// then rootpath should become 'less/../'
newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
if (newFileInfo.relativeUrls) {
newFileInfo.rootpath = fileManager.join(
(importManager.context.rootpath || ""),
fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
}
}
newFileInfo.filename = resolvedFilename;
var newEnv = new contexts.Parse(importManager.context);
newEnv.processImports = false;
importManager.contents[resolvedFilename] = contents;
if (currentFileInfo.reference || importOptions.reference) {
newFileInfo.reference = true;
}
if (importOptions.plugin) {
new FunctionImporter(newEnv, newFileInfo).eval(contents, function (e, root) {
fileParsedFunc(e, root, resolvedFilename);
});
} else if (importOptions.inline) {
fileParsedFunc(null, contents, resolvedFilename);
} else {
new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) {
fileParsedFunc(e, root, resolvedFilename);
});
}
};
var promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, this.context, environment,
function(err, loadedFile) {
if (err) {
fileParsedFunc(err);
} else {
loadFileCallback(loadedFile);
}
});
if (promise) {
promise.then(loadFileCallback, fileParsedFunc);
}
};
return ImportManager;
};

29
static/js/ketcher2/node_modules/less/lib/less/index.js generated vendored Normal file
View File

@ -0,0 +1,29 @@
module.exports = function(environment, fileManagers) {
var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
var less = {
version: [2, 7, 3],
data: require('./data'),
tree: require('./tree'),
Environment: (Environment = require("./environment/environment")),
AbstractFileManager: require("./environment/abstract-file-manager"),
environment: (environment = new Environment(environment, fileManagers)),
visitors: require('./visitors'),
Parser: require('./parser/parser'),
functions: require('./functions')(environment),
contexts: require("./contexts"),
SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)),
SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)),
ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)),
ImportManager: (ImportManager = require('./import-manager')(environment)),
render: require("./render")(environment, ParseTree, ImportManager),
parse: require("./parse")(environment, ParseTree, ImportManager),
LessError: require('./less-error'),
transformTree: require('./transform-tree'),
utils: require('./utils'),
PluginManager: require('./plugin-manager'),
logger: require('./logger')
};
return less;
};

View File

@ -0,0 +1,42 @@
var utils = require("./utils");
var LessError = module.exports = function LessError(e, importManager, currentFilename) {
Error.call(this);
var filename = e.filename || currentFilename;
if (importManager && filename) {
var input = importManager.contents[filename],
loc = utils.getLocation(e.index, input),
line = loc.line,
col = loc.column,
callLine = e.call && utils.getLocation(e.call, input).line,
lines = input.split('\n');
this.type = e.type || 'Syntax';
this.filename = filename;
this.index = e.index;
this.line = typeof line === 'number' ? line + 1 : null;
this.callLine = callLine + 1;
this.callExtract = lines[callLine];
this.column = col;
this.extract = [
lines[line - 1],
lines[line],
lines[line + 1]
];
}
this.message = e.message;
this.stack = e.stack;
};
if (typeof Object.create === 'undefined') {
var F = function () {};
F.prototype = Error.prototype;
LessError.prototype = new F();
} else {
LessError.prototype = Object.create(Error.prototype);
}
LessError.prototype.constructor = LessError;

View File

@ -0,0 +1,34 @@
module.exports = {
error: function(msg) {
this._fireEvent("error", msg);
},
warn: function(msg) {
this._fireEvent("warn", msg);
},
info: function(msg) {
this._fireEvent("info", msg);
},
debug: function(msg) {
this._fireEvent("debug", msg);
},
addListener: function(listener) {
this._listeners.push(listener);
},
removeListener: function(listener) {
for (var i = 0; i < this._listeners.length; i++) {
if (this._listeners[i] === listener) {
this._listeners.splice(i, 1);
return;
}
}
},
_fireEvent: function(type, msg) {
for (var i = 0; i < this._listeners.length; i++) {
var logFunction = this._listeners[i][type];
if (logFunction) {
logFunction(msg);
}
}
},
_listeners: []
};

View File

@ -0,0 +1,60 @@
var LessError = require('./less-error'),
transformTree = require("./transform-tree"),
logger = require("./logger");
module.exports = function(SourceMapBuilder) {
var ParseTree = function(root, imports) {
this.root = root;
this.imports = imports;
};
ParseTree.prototype.toCSS = function(options) {
var evaldRoot, result = {}, sourceMapBuilder;
try {
evaldRoot = transformTree(this.root, options);
} catch (e) {
throw new LessError(e, this.imports);
}
try {
var compress = Boolean(options.compress);
if (compress) {
logger.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");
}
var toCSSOptions = {
compress: compress,
dumpLineNumbers: options.dumpLineNumbers,
strictUnits: Boolean(options.strictUnits),
numPrecision: 8};
if (options.sourceMap) {
sourceMapBuilder = new SourceMapBuilder(options.sourceMap);
result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);
} else {
result.css = evaldRoot.toCSS(toCSSOptions);
}
} catch (e) {
throw new LessError(e, this.imports);
}
if (options.pluginManager) {
var postProcessors = options.pluginManager.getPostProcessors();
for (var i = 0; i < postProcessors.length; i++) {
result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports });
}
}
if (options.sourceMap) {
result.map = sourceMapBuilder.getExternalSourceMap();
}
result.imports = [];
for (var file in this.imports.files) {
if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) {
result.imports.push(file);
}
}
return result;
};
return ParseTree;
};

68
static/js/ketcher2/node_modules/less/lib/less/parse.js generated vendored Normal file
View File

@ -0,0 +1,68 @@
var PromiseConstructor,
contexts = require("./contexts"),
Parser = require('./parser/parser'),
PluginManager = require('./plugin-manager');
module.exports = function(environment, ParseTree, ImportManager) {
var parse = function (input, options, callback) {
options = options || {};
if (typeof options === 'function') {
callback = options;
options = {};
}
if (!callback) {
if (!PromiseConstructor) {
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
}
var self = this;
return new PromiseConstructor(function (resolve, reject) {
parse.call(self, input, options, function(err, output) {
if (err) {
reject(err);
} else {
resolve(output);
}
});
});
} else {
var context,
rootFileInfo,
pluginManager = new PluginManager(this);
pluginManager.addPlugins(options.plugins);
options.pluginManager = pluginManager;
context = new contexts.Parse(options);
if (options.rootFileInfo) {
rootFileInfo = options.rootFileInfo;
} else {
var filename = options.filename || "input";
var entryPath = filename.replace(/[^\/\\]*$/, "");
rootFileInfo = {
filename: filename,
relativeUrls: context.relativeUrls,
rootpath: context.rootpath || "",
currentDirectory: entryPath,
entryPath: entryPath,
rootFilename: filename
};
// add in a missing trailing slash
if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== "/") {
rootFileInfo.rootpath += "/";
}
}
var imports = new ImportManager(context, rootFileInfo);
new Parser(context, imports, rootFileInfo)
.parse(input, function (e, root) {
if (e) { return callback(e); }
callback(null, root, imports, options);
}, options);
}
};
return parse;
};

View File

@ -0,0 +1,112 @@
// Split the input into chunks.
module.exports = function (input, fail) {
var len = input.length, level = 0, parenLevel = 0,
lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
chunks = [], emitFrom = 0,
chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
function emitChunk(force) {
var len = chunkerCurrentIndex - emitFrom;
if (((len < 512) && !force) || !len) {
return;
}
chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));
emitFrom = chunkerCurrentIndex + 1;
}
for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc = input.charCodeAt(chunkerCurrentIndex);
if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
// a-z or whitespace
continue;
}
switch (cc) {
case 40: // (
parenLevel++;
lastOpeningParen = chunkerCurrentIndex;
continue;
case 41: // )
if (--parenLevel < 0) {
return fail("missing opening `(`", chunkerCurrentIndex);
}
continue;
case 59: // ;
if (!parenLevel) { emitChunk(); }
continue;
case 123: // {
level++;
lastOpening = chunkerCurrentIndex;
continue;
case 125: // }
if (--level < 0) {
return fail("missing opening `{`", chunkerCurrentIndex);
}
if (!level && !parenLevel) { emitChunk(); }
continue;
case 92: // \
if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; }
return fail("unescaped `\\`", chunkerCurrentIndex);
case 34:
case 39:
case 96: // ", ' and `
matched = 0;
currentChunkStartIndex = chunkerCurrentIndex;
for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if (cc2 > 96) { continue; }
if (cc2 == cc) { matched = 1; break; }
if (cc2 == 92) { // \
if (chunkerCurrentIndex == len - 1) {
return fail("unescaped `\\`", chunkerCurrentIndex);
}
chunkerCurrentIndex++;
}
}
if (matched) { continue; }
return fail("unmatched `" + String.fromCharCode(cc) + "`", currentChunkStartIndex);
case 47: // /, check for comment
if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; }
cc2 = input.charCodeAt(chunkerCurrentIndex + 1);
if (cc2 == 47) {
// //, find lnfeed
for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
}
} else if (cc2 == 42) {
// /*, find */
lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;
for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {
cc2 = input.charCodeAt(chunkerCurrentIndex);
if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; }
if (cc2 != 42) { continue; }
if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; }
}
if (chunkerCurrentIndex == len - 1) {
return fail("missing closing `*/`", currentChunkStartIndex);
}
chunkerCurrentIndex++;
}
continue;
case 42: // *, check for unmatched */
if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {
return fail("unmatched `/*`", chunkerCurrentIndex);
}
continue;
}
}
if (level !== 0) {
if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
return fail("missing closing `}` or `*/`", lastOpening);
} else {
return fail("missing closing `}`", lastOpening);
}
} else if (parenLevel !== 0) {
return fail("missing closing `)`", lastOpeningParen);
}
emitChunk(true);
return chunks;
};

View File

@ -0,0 +1,259 @@
var chunker = require('./chunker');
module.exports = function() {
var input, // LeSS input string
j, // current chunk
saveStack = [], // holds state for backtracking
furthest, // furthest index the parser has gone to
furthestPossibleErrorMessage,// if this is furthest we got to, this is the probably cause
chunks, // chunkified input
current, // current chunk
currentPos, // index of current chunk, in `input`
parserInput = {};
var CHARCODE_SPACE = 32,
CHARCODE_TAB = 9,
CHARCODE_LF = 10,
CHARCODE_CR = 13,
CHARCODE_PLUS = 43,
CHARCODE_COMMA = 44,
CHARCODE_FORWARD_SLASH = 47,
CHARCODE_9 = 57;
function skipWhitespace(length) {
var oldi = parserInput.i, oldj = j,
curr = parserInput.i - currentPos,
endIndex = parserInput.i + current.length - curr,
mem = (parserInput.i += length),
inp = input,
c, nextChar, comment;
for (; parserInput.i < endIndex; parserInput.i++) {
c = inp.charCodeAt(parserInput.i);
if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {
nextChar = inp.charAt(parserInput.i + 1);
if (nextChar === '/') {
comment = {index: parserInput.i, isLineComment: true};
var nextNewLine = inp.indexOf("\n", parserInput.i + 2);
if (nextNewLine < 0) {
nextNewLine = endIndex;
}
parserInput.i = nextNewLine;
comment.text = inp.substr(comment.index, parserInput.i - comment.index);
parserInput.commentStore.push(comment);
continue;
} else if (nextChar === '*') {
var nextStarSlash = inp.indexOf("*/", parserInput.i + 2);
if (nextStarSlash >= 0) {
comment = {
index: parserInput.i,
text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i),
isLineComment: false
};
parserInput.i += comment.text.length - 1;
parserInput.commentStore.push(comment);
continue;
}
}
break;
}
if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {
break;
}
}
current = current.slice(length + parserInput.i - mem + curr);
currentPos = parserInput.i;
if (!current.length) {
if (j < chunks.length - 1) {
current = chunks[++j];
skipWhitespace(0); // skip space at the beginning of a chunk
return true; // things changed
}
parserInput.finished = true;
}
return oldi !== parserInput.i || oldj !== j;
}
parserInput.save = function() {
currentPos = parserInput.i;
saveStack.push( { current: current, i: parserInput.i, j: j });
};
parserInput.restore = function(possibleErrorMessage) {
if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {
furthest = parserInput.i;
furthestPossibleErrorMessage = possibleErrorMessage;
}
var state = saveStack.pop();
current = state.current;
currentPos = parserInput.i = state.i;
j = state.j;
};
parserInput.forget = function() {
saveStack.pop();
};
parserInput.isWhitespace = function (offset) {
var pos = parserInput.i + (offset || 0),
code = input.charCodeAt(pos);
return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);
};
// Specialization of $(tok)
parserInput.$re = function(tok) {
if (parserInput.i > currentPos) {
current = current.slice(parserInput.i - currentPos);
currentPos = parserInput.i;
}
var m = tok.exec(current);
if (!m) {
return null;
}
skipWhitespace(m[0].length);
if (typeof m === "string") {
return m;
}
return m.length === 1 ? m[0] : m;
};
parserInput.$char = function(tok) {
if (input.charAt(parserInput.i) !== tok) {
return null;
}
skipWhitespace(1);
return tok;
};
parserInput.$str = function(tok) {
var tokLength = tok.length;
// https://jsperf.com/string-startswith/21
for (var i = 0; i < tokLength; i++) {
if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
return null;
}
}
skipWhitespace(tokLength);
return tok;
};
parserInput.$quoted = function() {
var startChar = input.charAt(parserInput.i);
if (startChar !== "'" && startChar !== '"') {
return;
}
var length = input.length,
currentPosition = parserInput.i;
for (var i = 1; i + currentPosition < length; i++) {
var nextChar = input.charAt(i + currentPosition);
switch(nextChar) {
case "\\":
i++;
continue;
case "\r":
case "\n":
break;
case startChar:
var str = input.substr(currentPosition, i + 1);
skipWhitespace(i + 1);
return str;
default:
}
}
return null;
};
parserInput.autoCommentAbsorb = true;
parserInput.commentStore = [];
parserInput.finished = false;
// Same as $(), but don't change the state of the parser,
// just return the match.
parserInput.peek = function(tok) {
if (typeof tok === 'string') {
// https://jsperf.com/string-startswith/21
for (var i = 0; i < tok.length; i++) {
if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
return false;
}
}
return true;
} else {
return tok.test(current);
}
};
// Specialization of peek()
// TODO remove or change some currentChar calls to peekChar
parserInput.peekChar = function(tok) {
return input.charAt(parserInput.i) === tok;
};
parserInput.currentChar = function() {
return input.charAt(parserInput.i);
};
parserInput.getInput = function() {
return input;
};
parserInput.peekNotNumeric = function() {
var c = input.charCodeAt(parserInput.i);
//Is the first char of the dimension 0-9, '.', '+' or '-'
return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
};
parserInput.start = function(str, chunkInput, failFunction) {
input = str;
parserInput.i = j = currentPos = furthest = 0;
// chunking apparently makes things quicker (but my tests indicate
// it might actually make things slower in node at least)
// and it is a non-perfect parse - it can't recognise
// unquoted urls, meaning it can't distinguish comments
// meaning comments with quotes or {}() in them get 'counted'
// and then lead to parse errors.
// In addition if the chunking chunks in the wrong place we might
// not be able to parse a parser statement in one go
// this is officially deprecated but can be switched on via an option
// in the case it causes too much performance issues.
if (chunkInput) {
chunks = chunker(str, failFunction);
} else {
chunks = [str];
}
current = chunks[0];
skipWhitespace(0);
};
parserInput.end = function() {
var message,
isFinished = parserInput.i >= input.length;
if (parserInput.i < furthest) {
message = furthestPossibleErrorMessage;
parserInput.i = furthest;
}
return {
isFinished: isFinished,
furthest: parserInput.i,
furthestPossibleErrorMessage: message,
furthestReachedEnd: parserInput.i >= input.length - 1,
furthestChar: input[parserInput.i]
};
};
return parserInput;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
/**
* Plugin Manager
*/
var PluginManager = function(less) {
this.less = less;
this.visitors = [];
this.preProcessors = [];
this.postProcessors = [];
this.installedPlugins = [];
this.fileManagers = [];
};
/**
* Adds all the plugins in the array
* @param {Array} plugins
*/
PluginManager.prototype.addPlugins = function(plugins) {
if (plugins) {
for (var i = 0; i < plugins.length; i++) {
this.addPlugin(plugins[i]);
}
}
};
/**
*
* @param plugin
*/
PluginManager.prototype.addPlugin = function(plugin) {
this.installedPlugins.push(plugin);
plugin.install(this.less, this);
};
/**
* Adds a visitor. The visitor object has options on itself to determine
* when it should run.
* @param visitor
*/
PluginManager.prototype.addVisitor = function(visitor) {
this.visitors.push(visitor);
};
/**
* Adds a pre processor object
* @param {object} preProcessor
* @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import
*/
PluginManager.prototype.addPreProcessor = function(preProcessor, priority) {
var indexToInsertAt;
for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) {
if (this.preProcessors[indexToInsertAt].priority >= priority) {
break;
}
}
this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority});
};
/**
* Adds a post processor object
* @param {object} postProcessor
* @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression
*/
PluginManager.prototype.addPostProcessor = function(postProcessor, priority) {
var indexToInsertAt;
for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {
if (this.postProcessors[indexToInsertAt].priority >= priority) {
break;
}
}
this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority});
};
/**
*
* @param manager
*/
PluginManager.prototype.addFileManager = function(manager) {
this.fileManagers.push(manager);
};
/**
*
* @returns {Array}
* @private
*/
PluginManager.prototype.getPreProcessors = function() {
var preProcessors = [];
for (var i = 0; i < this.preProcessors.length; i++) {
preProcessors.push(this.preProcessors[i].preProcessor);
}
return preProcessors;
};
/**
*
* @returns {Array}
* @private
*/
PluginManager.prototype.getPostProcessors = function() {
var postProcessors = [];
for (var i = 0; i < this.postProcessors.length; i++) {
postProcessors.push(this.postProcessors[i].postProcessor);
}
return postProcessors;
};
/**
*
* @returns {Array}
* @private
*/
PluginManager.prototype.getVisitors = function() {
return this.visitors;
};
/**
*
* @returns {Array}
* @private
*/
PluginManager.prototype.getFileManagers = function() {
return this.fileManagers;
};
module.exports = PluginManager;

View File

@ -0,0 +1,35 @@
var LessError = require('../less-error'),
tree = require("../tree");
var FunctionImporter = module.exports = function FunctionImporter(context, fileInfo) {
this.fileInfo = fileInfo;
};
FunctionImporter.prototype.eval = function(contents, callback) {
var loaded = {},
loader,
registry;
registry = {
add: function(name, func) {
loaded[name] = func;
},
addMultiple: function(functions) {
Object.keys(functions).forEach(function(name) {
loaded[name] = functions[name];
});
}
};
try {
loader = new Function("functions", "tree", "fileInfo", contents);
loader(registry, tree, this.fileInfo);
} catch(e) {
callback(new LessError({
message: "Plugin evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
filename: this.fileInfo.filename
}), null );
}
callback(null, { functions: loaded });
};

View File

@ -0,0 +1,41 @@
var PromiseConstructor;
module.exports = function(environment, ParseTree, ImportManager) {
var render = function (input, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (!callback) {
if (!PromiseConstructor) {
PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
}
var self = this;
return new PromiseConstructor(function (resolve, reject) {
render.call(self, input, options, function(err, output) {
if (err) {
reject(err);
} else {
resolve(output);
}
});
});
} else {
this.parse(input, options, function(err, root, imports, options) {
if (err) { return callback(err); }
var result;
try {
var parseTree = new ParseTree(root, imports);
result = parseTree.toCSS(options);
}
catch (err) { return callback(err); }
callback(null, result);
});
}
};
return render;
};

View File

@ -0,0 +1,69 @@
module.exports = function (SourceMapOutput, environment) {
var SourceMapBuilder = function (options) {
this.options = options;
};
SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) {
var sourceMapOutput = new SourceMapOutput(
{
contentsIgnoredCharsMap: imports.contentsIgnoredChars,
rootNode: rootNode,
contentsMap: imports.contents,
sourceMapFilename: this.options.sourceMapFilename,
sourceMapURL: this.options.sourceMapURL,
outputFilename: this.options.sourceMapOutputFilename,
sourceMapBasepath: this.options.sourceMapBasepath,
sourceMapRootpath: this.options.sourceMapRootpath,
outputSourceFiles: this.options.outputSourceFiles,
sourceMapGenerator: this.options.sourceMapGenerator,
sourceMapFileInline: this.options.sourceMapFileInline
});
var css = sourceMapOutput.toCSS(options);
this.sourceMap = sourceMapOutput.sourceMap;
this.sourceMapURL = sourceMapOutput.sourceMapURL;
if (this.options.sourceMapInputFilename) {
this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename);
}
return css + this.getCSSAppendage();
};
SourceMapBuilder.prototype.getCSSAppendage = function() {
var sourceMapURL = this.sourceMapURL;
if (this.options.sourceMapFileInline) {
if (this.sourceMap === undefined) {
return "";
}
sourceMapURL = "data:application/json;base64," + environment.encodeBase64(this.sourceMap);
}
if (sourceMapURL) {
return "/*# sourceMappingURL=" + sourceMapURL + " */";
}
return "";
};
SourceMapBuilder.prototype.getExternalSourceMap = function() {
return this.sourceMap;
};
SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) {
this.sourceMap = sourceMap;
};
SourceMapBuilder.prototype.isInline = function() {
return this.options.sourceMapFileInline;
};
SourceMapBuilder.prototype.getSourceMapURL = function() {
return this.sourceMapURL;
};
SourceMapBuilder.prototype.getOutputFilename = function() {
return this.options.sourceMapOutputFilename;
};
SourceMapBuilder.prototype.getInputFilename = function() {
return this.sourceMapInputFilename;
};
return SourceMapBuilder;
};

View File

@ -0,0 +1,138 @@
module.exports = function (environment) {
var SourceMapOutput = function (options) {
this._css = [];
this._rootNode = options.rootNode;
this._contentsMap = options.contentsMap;
this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap;
if (options.sourceMapFilename) {
this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/');
}
this._outputFilename = options.outputFilename;
this.sourceMapURL = options.sourceMapURL;
if (options.sourceMapBasepath) {
this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/');
}
if (options.sourceMapRootpath) {
this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
this._sourceMapRootpath += '/';
}
} else {
this._sourceMapRootpath = "";
}
this._outputSourceFiles = options.outputSourceFiles;
this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator();
this._lineNumber = 0;
this._column = 0;
};
SourceMapOutput.prototype.normalizeFilename = function(filename) {
filename = filename.replace(/\\/g, '/');
if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
filename = filename.substring(this._sourceMapBasepath.length);
if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
filename = filename.substring(1);
}
}
return (this._sourceMapRootpath || "") + filename;
};
SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
//ignore adding empty strings
if (!chunk) {
return;
}
var lines,
sourceLines,
columns,
sourceColumns,
i;
if (fileInfo) {
var inputSource = this._contentsMap[fileInfo.filename];
// remove vars/banner added to the top of the file
if (this._contentsIgnoredCharsMap[fileInfo.filename]) {
// adjust the index
index -= this._contentsIgnoredCharsMap[fileInfo.filename];
if (index < 0) { index = 0; }
// adjust the source
inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]);
}
inputSource = inputSource.substring(0, index);
sourceLines = inputSource.split("\n");
sourceColumns = sourceLines[sourceLines.length - 1];
}
lines = chunk.split("\n");
columns = lines[lines.length - 1];
if (fileInfo) {
if (!mapLines) {
this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
original: { line: sourceLines.length, column: sourceColumns.length},
source: this.normalizeFilename(fileInfo.filename)});
} else {
for (i = 0; i < lines.length; i++) {
this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
source: this.normalizeFilename(fileInfo.filename)});
}
}
}
if (lines.length === 1) {
this._column += columns.length;
} else {
this._lineNumber += lines.length - 1;
this._column = columns.length;
}
this._css.push(chunk);
};
SourceMapOutput.prototype.isEmpty = function() {
return this._css.length === 0;
};
SourceMapOutput.prototype.toCSS = function(context) {
this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
if (this._outputSourceFiles) {
for (var filename in this._contentsMap) {
if (this._contentsMap.hasOwnProperty(filename)) {
var source = this._contentsMap[filename];
if (this._contentsIgnoredCharsMap[filename]) {
source = source.slice(this._contentsIgnoredCharsMap[filename]);
}
this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source);
}
}
}
this._rootNode.genCSS(context, this);
if (this._css.length > 0) {
var sourceMapURL,
sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
if (this.sourceMapURL) {
sourceMapURL = this.sourceMapURL;
} else if (this._sourceMapFilename) {
sourceMapURL = this._sourceMapFilename;
}
this.sourceMapURL = sourceMapURL;
this.sourceMap = sourceMapContent;
}
return this._css.join('');
};
return SourceMapOutput;
};

View File

@ -0,0 +1,74 @@
var contexts = require("./contexts"),
visitor = require("./visitors"),
tree = require("./tree");
module.exports = function(root, options) {
options = options || {};
var evaldRoot,
variables = options.variables,
evalEnv = new contexts.Eval(options);
//
// Allows setting variables with a hash, so:
//
// `{ color: new tree.Color('#f01') }` will become:
//
// new tree.Rule('@color',
// new tree.Value([
// new tree.Expression([
// new tree.Color('#f01')
// ])
// ])
// )
//
if (typeof variables === 'object' && !Array.isArray(variables)) {
variables = Object.keys(variables).map(function (k) {
var value = variables[k];
if (! (value instanceof tree.Value)) {
if (! (value instanceof tree.Expression)) {
value = new tree.Expression([value]);
}
value = new tree.Value([value]);
}
return new tree.Rule('@' + k, value, false, null, 0);
});
evalEnv.frames = [new tree.Ruleset(null, variables)];
}
var preEvalVisitors = [],
visitors = [
new visitor.JoinSelectorVisitor(),
new visitor.MarkVisibleSelectorsVisitor(true),
new visitor.ExtendVisitor(),
new visitor.ToCSSVisitor({compress: Boolean(options.compress)})
], i;
if (options.pluginManager) {
var pluginVisitors = options.pluginManager.getVisitors();
for (i = 0; i < pluginVisitors.length; i++) {
var pluginVisitor = pluginVisitors[i];
if (pluginVisitor.isPreEvalVisitor) {
preEvalVisitors.push(pluginVisitor);
} else {
if (pluginVisitor.isPreVisitor) {
visitors.splice(0, 0, pluginVisitor);
} else {
visitors.push(pluginVisitor);
}
}
}
}
for (i = 0; i < preEvalVisitors.length; i++) {
preEvalVisitors[i].run(root);
}
evaldRoot = root.eval(evalEnv);
for (i = 0; i < visitors.length; i++) {
visitors[i].run(evaldRoot);
}
return evaldRoot;
};

View File

@ -0,0 +1,28 @@
var Node = require("./node");
var Alpha = function (val) {
this.value = val;
};
Alpha.prototype = new Node();
Alpha.prototype.type = "Alpha";
Alpha.prototype.accept = function (visitor) {
this.value = visitor.visit(this.value);
};
Alpha.prototype.eval = function (context) {
if (this.value.eval) { return new Alpha(this.value.eval(context)); }
return this;
};
Alpha.prototype.genCSS = function (context, output) {
output.add("alpha(opacity=");
if (this.value.genCSS) {
this.value.genCSS(context, output);
} else {
output.add(this.value);
}
output.add(")");
};
module.exports = Alpha;

View File

@ -0,0 +1,26 @@
var Node = require("./node");
var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) {
this.value = value;
this.index = index;
this.mapLines = mapLines;
this.currentFileInfo = currentFileInfo;
this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : rulesetLike;
this.allowRoot = true;
this.copyVisibilityInfo(visibilityInfo);
};
Anonymous.prototype = new Node();
Anonymous.prototype.type = "Anonymous";
Anonymous.prototype.eval = function () {
return new Anonymous(this.value, this.index, this.currentFileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo());
};
Anonymous.prototype.compare = function (other) {
return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
};
Anonymous.prototype.isRulesetLike = function() {
return this.rulesetLike;
};
Anonymous.prototype.genCSS = function (context, output) {
output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
};
module.exports = Anonymous;

View File

@ -0,0 +1,27 @@
var Node = require("./node");
var Assignment = function (key, val) {
this.key = key;
this.value = val;
};
Assignment.prototype = new Node();
Assignment.prototype.type = "Assignment";
Assignment.prototype.accept = function (visitor) {
this.value = visitor.visit(this.value);
};
Assignment.prototype.eval = function (context) {
if (this.value.eval) {
return new Assignment(this.key, this.value.eval(context));
}
return this;
};
Assignment.prototype.genCSS = function (context, output) {
output.add(this.key + '=');
if (this.value.genCSS) {
this.value.genCSS(context, output);
} else {
output.add(this.value);
}
};
module.exports = Assignment;

View File

@ -0,0 +1,27 @@
var Node = require("./node");
var Attribute = function (key, op, value) {
this.key = key;
this.op = op;
this.value = value;
};
Attribute.prototype = new Node();
Attribute.prototype.type = "Attribute";
Attribute.prototype.eval = function (context) {
return new Attribute(this.key.eval ? this.key.eval(context) : this.key,
this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value);
};
Attribute.prototype.genCSS = function (context, output) {
output.add(this.toCSS(context));
};
Attribute.prototype.toCSS = function (context) {
var value = this.key.toCSS ? this.key.toCSS(context) : this.key;
if (this.op) {
value += this.op;
value += (this.value.toCSS ? this.value.toCSS(context) : this.value);
}
return '[' + value + ']';
};
module.exports = Attribute;

View File

@ -0,0 +1,65 @@
var Node = require("./node"),
FunctionCaller = require("../functions/function-caller");
//
// A function call node.
//
var Call = function (name, args, index, currentFileInfo) {
this.name = name;
this.args = args;
this.index = index;
this.currentFileInfo = currentFileInfo;
};
Call.prototype = new Node();
Call.prototype.type = "Call";
Call.prototype.accept = function (visitor) {
if (this.args) {
this.args = visitor.visitArray(this.args);
}
};
//
// When evaluating a function call,
// we either find the function in the functionRegistry,
// in which case we call it, passing the evaluated arguments,
// if this returns null or we cannot find the function, we
// simply print it out as it appeared originally [2].
//
// The reason why we evaluate the arguments, is in the case where
// we try to pass a variable to a function, like: `saturate(@color)`.
// The function should receive the value, not the variable.
//
Call.prototype.eval = function (context) {
var args = this.args.map(function (a) { return a.eval(context); }),
result, funcCaller = new FunctionCaller(this.name, context, this.index, this.currentFileInfo);
if (funcCaller.isValid()) {
try {
result = funcCaller.call(args);
} catch (e) {
throw { type: e.type || "Runtime",
message: "error evaluating function `" + this.name + "`" +
(e.message ? ': ' + e.message : ''),
index: this.index, filename: this.currentFileInfo.filename };
}
if (result != null) {
result.index = this.index;
result.currentFileInfo = this.currentFileInfo;
return result;
}
}
return new Call(this.name, args, this.index, this.currentFileInfo);
};
Call.prototype.genCSS = function (context, output) {
output.add(this.name + "(", this.currentFileInfo, this.index);
for (var i = 0; i < this.args.length; i++) {
this.args[i].genCSS(context, output);
if (i + 1 < this.args.length) {
output.add(", ");
}
}
output.add(")");
};
module.exports = Call;

View File

@ -0,0 +1,189 @@
var Node = require("./node"),
colors = require("../data/colors");
//
// RGB Colors - #ff0014, #eee
//
var Color = function (rgb, a, originalForm) {
//
// The end goal here, is to parse the arguments
// into an integer triplet, such as `128, 255, 0`
//
// This facilitates operations and conversions.
//
if (Array.isArray(rgb)) {
this.rgb = rgb;
} else if (rgb.length == 6) {
this.rgb = rgb.match(/.{2}/g).map(function (c) {
return parseInt(c, 16);
});
} else {
this.rgb = rgb.split('').map(function (c) {
return parseInt(c + c, 16);
});
}
this.alpha = typeof a === 'number' ? a : 1;
if (typeof originalForm !== 'undefined') {
this.value = originalForm;
}
};
Color.prototype = new Node();
Color.prototype.type = "Color";
function clamp(v, max) {
return Math.min(Math.max(v, 0), max);
}
function toHex(v) {
return '#' + v.map(function (c) {
c = clamp(Math.round(c), 255);
return (c < 16 ? '0' : '') + c.toString(16);
}).join('');
}
Color.prototype.luma = function () {
var r = this.rgb[0] / 255,
g = this.rgb[1] / 255,
b = this.rgb[2] / 255;
r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};
Color.prototype.genCSS = function (context, output) {
output.add(this.toCSS(context));
};
Color.prototype.toCSS = function (context, doNotCompress) {
var compress = context && context.compress && !doNotCompress, color, alpha;
// `value` is set if this color was originally
// converted from a named color string so we need
// to respect this and try to output named color too.
if (this.value) {
return this.value;
}
// If we have some transparency, the only way to represent it
// is via `rgba`. Otherwise, we use the hex representation,
// which has better compatibility with older browsers.
// Values are capped between `0` and `255`, rounded and zero-padded.
alpha = this.fround(context, this.alpha);
if (alpha < 1) {
return "rgba(" + this.rgb.map(function (c) {
return clamp(Math.round(c), 255);
}).concat(clamp(alpha, 1))
.join(',' + (compress ? '' : ' ')) + ")";
}
color = this.toRGB();
if (compress) {
var splitcolor = color.split('');
// Convert color to short format
if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
}
}
return color;
};
//
// Operations have to be done per-channel, if not,
// channels will spill onto each other. Once we have
// our result, in the form of an integer triplet,
// we create a new Color node to hold the result.
//
Color.prototype.operate = function (context, op, other) {
var rgb = [];
var alpha = this.alpha * (1 - other.alpha) + other.alpha;
for (var c = 0; c < 3; c++) {
rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]);
}
return new Color(rgb, alpha);
};
Color.prototype.toRGB = function () {
return toHex(this.rgb);
};
Color.prototype.toHSL = function () {
var r = this.rgb[0] / 255,
g = this.rgb[1] / 255,
b = this.rgb[2] / 255,
a = this.alpha;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2, d = max - min;
if (max === min) {
h = s = 0;
} else {
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h * 360, s: s, l: l, a: a };
};
//Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
Color.prototype.toHSV = function () {
var r = this.rgb[0] / 255,
g = this.rgb[1] / 255,
b = this.rgb[2] / 255,
a = this.alpha;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, v = max;
var d = max - min;
if (max === 0) {
s = 0;
} else {
s = d / max;
}
if (max === min) {
h = 0;
} else {
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h * 360, s: s, v: v, a: a };
};
Color.prototype.toARGB = function () {
return toHex([this.alpha * 255].concat(this.rgb));
};
Color.prototype.compare = function (x) {
return (x.rgb &&
x.rgb[0] === this.rgb[0] &&
x.rgb[1] === this.rgb[1] &&
x.rgb[2] === this.rgb[2] &&
x.alpha === this.alpha) ? 0 : undefined;
};
Color.fromKeyword = function(keyword) {
var c, key = keyword.toLowerCase();
if (colors.hasOwnProperty(key)) {
c = new Color(colors[key].slice(1));
}
else if (key === "transparent") {
c = new Color([0, 0, 0], 0);
}
if (c) {
c.value = keyword;
return c;
}
};
module.exports = Color;

View File

@ -0,0 +1,23 @@
var Node = require("./node");
var Combinator = function (value) {
if (value === ' ') {
this.value = ' ';
this.emptyOrWhitespace = true;
} else {
this.value = value ? value.trim() : "";
this.emptyOrWhitespace = this.value === "";
}
};
Combinator.prototype = new Node();
Combinator.prototype.type = "Combinator";
var _noSpaceCombinators = {
'': true,
' ': true,
'|': true
};
Combinator.prototype.genCSS = function (context, output) {
var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' ';
output.add(spaceOrEmpty + this.value + spaceOrEmpty);
};
module.exports = Combinator;

View File

@ -0,0 +1,23 @@
var Node = require("./node"),
getDebugInfo = require("./debug-info");
var Comment = function (value, isLineComment, index, currentFileInfo) {
this.value = value;
this.isLineComment = isLineComment;
this.index = index;
this.currentFileInfo = currentFileInfo;
this.allowRoot = true;
};
Comment.prototype = new Node();
Comment.prototype.type = "Comment";
Comment.prototype.genCSS = function (context, output) {
if (this.debugInfo) {
output.add(getDebugInfo(context, this), this.currentFileInfo, this.index);
}
output.add(this.value);
};
Comment.prototype.isSilent = function(context) {
var isCompressed = context.compress && this.value[2] !== "!";
return this.isLineComment || isCompressed;
};
module.exports = Comment;

View File

@ -0,0 +1,37 @@
var Node = require("./node");
var Condition = function (op, l, r, i, negate) {
this.op = op.trim();
this.lvalue = l;
this.rvalue = r;
this.index = i;
this.negate = negate;
};
Condition.prototype = new Node();
Condition.prototype.type = "Condition";
Condition.prototype.accept = function (visitor) {
this.lvalue = visitor.visit(this.lvalue);
this.rvalue = visitor.visit(this.rvalue);
};
Condition.prototype.eval = function (context) {
var result = (function (op, a, b) {
switch (op) {
case 'and': return a && b;
case 'or': return a || b;
default:
switch (Node.compare(a, b)) {
case -1:
return op === '<' || op === '=<' || op === '<=';
case 0:
return op === '=' || op === '>=' || op === '=<' || op === '<=';
case 1:
return op === '>' || op === '>=';
default:
return false;
}
}
})(this.op, this.lvalue.eval(context), this.rvalue.eval(context));
return this.negate ? !result : result;
};
module.exports = Condition;

View File

@ -0,0 +1,38 @@
var debugInfo = function(context, ctx, lineSeparator) {
var result = "";
if (context.dumpLineNumbers && !context.compress) {
switch(context.dumpLineNumbers) {
case 'comments':
result = debugInfo.asComment(ctx);
break;
case 'mediaquery':
result = debugInfo.asMediaQuery(ctx);
break;
case 'all':
result = debugInfo.asComment(ctx) + (lineSeparator || "") + debugInfo.asMediaQuery(ctx);
break;
}
}
return result;
};
debugInfo.asComment = function(ctx) {
return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
};
debugInfo.asMediaQuery = function(ctx) {
var filenameWithProtocol = ctx.debugInfo.fileName;
if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
filenameWithProtocol = 'file://' + filenameWithProtocol;
}
return '@media -sass-debug-info{filename{font-family:' +
filenameWithProtocol.replace(/([.:\/\\])/g, function (a) {
if (a == '\\') {
a = '\/';
}
return '\\' + a;
}) +
'}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
};
module.exports = debugInfo;

View File

@ -0,0 +1,21 @@
var Node = require("./node"),
contexts = require("../contexts");
var DetachedRuleset = function (ruleset, frames) {
this.ruleset = ruleset;
this.frames = frames;
};
DetachedRuleset.prototype = new Node();
DetachedRuleset.prototype.type = "DetachedRuleset";
DetachedRuleset.prototype.evalFirst = true;
DetachedRuleset.prototype.accept = function (visitor) {
this.ruleset = visitor.visit(this.ruleset);
};
DetachedRuleset.prototype.eval = function (context) {
var frames = this.frames || context.frames.slice(0);
return new DetachedRuleset(this.ruleset, frames);
};
DetachedRuleset.prototype.callEval = function (context) {
return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context);
};
module.exports = DetachedRuleset;

View File

@ -0,0 +1,157 @@
var Node = require("./node"),
unitConversions = require("../data/unit-conversions"),
Unit = require("./unit"),
Color = require("./color");
//
// A number with a unit
//
var Dimension = function (value, unit) {
this.value = parseFloat(value);
this.unit = (unit && unit instanceof Unit) ? unit :
new Unit(unit ? [unit] : undefined);
};
Dimension.prototype = new Node();
Dimension.prototype.type = "Dimension";
Dimension.prototype.accept = function (visitor) {
this.unit = visitor.visit(this.unit);
};
Dimension.prototype.eval = function (context) {
return this;
};
Dimension.prototype.toColor = function () {
return new Color([this.value, this.value, this.value]);
};
Dimension.prototype.genCSS = function (context, output) {
if ((context && context.strictUnits) && !this.unit.isSingular()) {
throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: " + this.unit.toString());
}
var value = this.fround(context, this.value),
strValue = String(value);
if (value !== 0 && value < 0.000001 && value > -0.000001) {
// would be output 1e-6 etc.
strValue = value.toFixed(20).replace(/0+$/, "");
}
if (context && context.compress) {
// Zero values doesn't need a unit
if (value === 0 && this.unit.isLength()) {
output.add(strValue);
return;
}
// Float values doesn't need a leading zero
if (value > 0 && value < 1) {
strValue = (strValue).substr(1);
}
}
output.add(strValue);
this.unit.genCSS(context, output);
};
// In an operation between two Dimensions,
// we default to the first Dimension's unit,
// so `1px + 2` will yield `3px`.
Dimension.prototype.operate = function (context, op, other) {
/*jshint noempty:false */
var value = this._operate(context, op, this.value, other.value),
unit = this.unit.clone();
if (op === '+' || op === '-') {
if (unit.numerator.length === 0 && unit.denominator.length === 0) {
unit = other.unit.clone();
if (this.unit.backupUnit) {
unit.backupUnit = this.unit.backupUnit;
}
} else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
// do nothing
} else {
other = other.convertTo(this.unit.usedUnits());
if (context.strictUnits && other.unit.toString() !== unit.toString()) {
throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() +
"' and '" + other.unit.toString() + "'.");
}
value = this._operate(context, op, this.value, other.value);
}
} else if (op === '*') {
unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
unit.cancel();
} else if (op === '/') {
unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
unit.cancel();
}
return new Dimension(value, unit);
};
Dimension.prototype.compare = function (other) {
var a, b;
if (!(other instanceof Dimension)) {
return undefined;
}
if (this.unit.isEmpty() || other.unit.isEmpty()) {
a = this;
b = other;
} else {
a = this.unify();
b = other.unify();
if (a.unit.compare(b.unit) !== 0) {
return undefined;
}
}
return Node.numericCompare(a.value, b.value);
};
Dimension.prototype.unify = function () {
return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
};
Dimension.prototype.convertTo = function (conversions) {
var value = this.value, unit = this.unit.clone(),
i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
if (typeof conversions === 'string') {
for (i in unitConversions) {
if (unitConversions[i].hasOwnProperty(conversions)) {
derivedConversions = {};
derivedConversions[i] = conversions;
}
}
conversions = derivedConversions;
}
applyUnit = function (atomicUnit, denominator) {
/* jshint loopfunc:true */
if (group.hasOwnProperty(atomicUnit)) {
if (denominator) {
value = value / (group[atomicUnit] / group[targetUnit]);
} else {
value = value * (group[atomicUnit] / group[targetUnit]);
}
return targetUnit;
}
return atomicUnit;
};
for (groupName in conversions) {
if (conversions.hasOwnProperty(groupName)) {
targetUnit = conversions[groupName];
group = unitConversions[groupName];
unit.map(applyUnit);
}
}
unit.cancel();
return new Dimension(value, unit);
};
module.exports = Dimension;

View File

@ -0,0 +1,134 @@
var Node = require("./node"),
Selector = require("./selector"),
Ruleset = require("./ruleset");
var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) {
var i;
this.name = name;
this.value = value;
if (rules) {
if (Array.isArray(rules)) {
this.rules = rules;
} else {
this.rules = [rules];
this.rules[0].selectors = (new Selector([], null, null, this.index, currentFileInfo)).createEmptySelectors();
}
for (i = 0; i < this.rules.length; i++) {
this.rules[i].allowImports = true;
}
}
this.index = index;
this.currentFileInfo = currentFileInfo;
this.debugInfo = debugInfo;
this.isRooted = isRooted || false;
this.copyVisibilityInfo(visibilityInfo);
this.allowRoot = true;
};
Directive.prototype = new Node();
Directive.prototype.type = "Directive";
Directive.prototype.accept = function (visitor) {
var value = this.value, rules = this.rules;
if (rules) {
this.rules = visitor.visitArray(rules);
}
if (value) {
this.value = visitor.visit(value);
}
};
Directive.prototype.isRulesetLike = function() {
return this.rules || !this.isCharset();
};
Directive.prototype.isCharset = function() {
return "@charset" === this.name;
};
Directive.prototype.genCSS = function (context, output) {
var value = this.value, rules = this.rules;
output.add(this.name, this.currentFileInfo, this.index);
if (value) {
output.add(' ');
value.genCSS(context, output);
}
if (rules) {
this.outputRuleset(context, output, rules);
} else {
output.add(';');
}
};
Directive.prototype.eval = function (context) {
var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
//media stored inside other directive should not bubble over it
//backpup media bubbling information
mediaPathBackup = context.mediaPath;
mediaBlocksBackup = context.mediaBlocks;
//deleted media bubbling information
context.mediaPath = [];
context.mediaBlocks = [];
if (value) {
value = value.eval(context);
}
if (rules) {
// assuming that there is only one rule at this point - that is how parser constructs the rule
rules = [rules[0].eval(context)];
rules[0].root = true;
}
//restore media bubbling information
context.mediaPath = mediaPathBackup;
context.mediaBlocks = mediaBlocksBackup;
return new Directive(this.name, value, rules,
this.index, this.currentFileInfo, this.debugInfo, this.isRooted, this.visibilityInfo());
};
Directive.prototype.variable = function (name) {
if (this.rules) {
// assuming that there is only one rule at this point - that is how parser constructs the rule
return Ruleset.prototype.variable.call(this.rules[0], name);
}
};
Directive.prototype.find = function () {
if (this.rules) {
// assuming that there is only one rule at this point - that is how parser constructs the rule
return Ruleset.prototype.find.apply(this.rules[0], arguments);
}
};
Directive.prototype.rulesets = function () {
if (this.rules) {
// assuming that there is only one rule at this point - that is how parser constructs the rule
return Ruleset.prototype.rulesets.apply(this.rules[0]);
}
};
Directive.prototype.outputRuleset = function (context, output, rules) {
var ruleCnt = rules.length, i;
context.tabLevel = (context.tabLevel | 0) + 1;
// Compressed
if (context.compress) {
output.add('{');
for (i = 0; i < ruleCnt; i++) {
rules[i].genCSS(context, output);
}
output.add('}');
context.tabLevel--;
return;
}
// Non-compressed
var tabSetStr = '\n' + Array(context.tabLevel).join(" "), tabRuleStr = tabSetStr + " ";
if (!ruleCnt) {
output.add(" {" + tabSetStr + '}');
} else {
output.add(" {" + tabRuleStr);
rules[0].genCSS(context, output);
for (i = 1; i < ruleCnt; i++) {
output.add(tabRuleStr);
rules[i].genCSS(context, output);
}
output.add(tabSetStr + '}');
}
context.tabLevel--;
};
module.exports = Directive;

View File

@ -0,0 +1,60 @@
var Node = require("./node"),
Paren = require("./paren"),
Combinator = require("./combinator");
var Element = function (combinator, value, index, currentFileInfo, info) {
this.combinator = combinator instanceof Combinator ?
combinator : new Combinator(combinator);
if (typeof value === 'string') {
this.value = value.trim();
} else if (value) {
this.value = value;
} else {
this.value = "";
}
this.index = index;
this.currentFileInfo = currentFileInfo;
this.copyVisibilityInfo(info);
};
Element.prototype = new Node();
Element.prototype.type = "Element";
Element.prototype.accept = function (visitor) {
var value = this.value;
this.combinator = visitor.visit(this.combinator);
if (typeof value === "object") {
this.value = visitor.visit(value);
}
};
Element.prototype.eval = function (context) {
return new Element(this.combinator,
this.value.eval ? this.value.eval(context) : this.value,
this.index,
this.currentFileInfo, this.visibilityInfo());
};
Element.prototype.clone = function () {
return new Element(this.combinator,
this.value,
this.index,
this.currentFileInfo, this.visibilityInfo());
};
Element.prototype.genCSS = function (context, output) {
output.add(this.toCSS(context), this.currentFileInfo, this.index);
};
Element.prototype.toCSS = function (context) {
context = context || {};
var value = this.value, firstSelector = context.firstSelector;
if (value instanceof Paren) {
// selector in parens should not be affected by outer selector
// flags (breaks only interpolated selectors - see #1973)
context.firstSelector = true;
}
value = value.toCSS ? value.toCSS(context) : value;
context.firstSelector = firstSelector;
if (value === '' && this.combinator.value.charAt(0) === '&') {
return '';
} else {
return this.combinator.toCSS(context) + value;
}
};
module.exports = Element;

View File

@ -0,0 +1,56 @@
var Node = require("./node"),
Paren = require("./paren"),
Comment = require("./comment");
var Expression = function (value) {
this.value = value;
if (!value) {
throw new Error("Expression requires an array parameter");
}
};
Expression.prototype = new Node();
Expression.prototype.type = "Expression";
Expression.prototype.accept = function (visitor) {
this.value = visitor.visitArray(this.value);
};
Expression.prototype.eval = function (context) {
var returnValue,
inParenthesis = this.parens && !this.parensInOp,
doubleParen = false;
if (inParenthesis) {
context.inParenthesis();
}
if (this.value.length > 1) {
returnValue = new Expression(this.value.map(function (e) {
return e.eval(context);
}));
} else if (this.value.length === 1) {
if (this.value[0].parens && !this.value[0].parensInOp) {
doubleParen = true;
}
returnValue = this.value[0].eval(context);
} else {
returnValue = this;
}
if (inParenthesis) {
context.outOfParenthesis();
}
if (this.parens && this.parensInOp && !(context.isMathOn()) && !doubleParen) {
returnValue = new Paren(returnValue);
}
return returnValue;
};
Expression.prototype.genCSS = function (context, output) {
for (var i = 0; i < this.value.length; i++) {
this.value[i].genCSS(context, output);
if (i + 1 < this.value.length) {
output.add(" ");
}
}
};
Expression.prototype.throwAwayComments = function () {
this.value = this.value.filter(function(v) {
return !(v instanceof Comment);
});
};
module.exports = Expression;

View File

@ -0,0 +1,57 @@
var Node = require("./node"),
Selector = require("./selector");
var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) {
this.selector = selector;
this.option = option;
this.index = index;
this.object_id = Extend.next_id++;
this.parent_ids = [this.object_id];
this.currentFileInfo = currentFileInfo || {};
this.copyVisibilityInfo(visibilityInfo);
this.allowRoot = true;
switch(option) {
case "all":
this.allowBefore = true;
this.allowAfter = true;
break;
default:
this.allowBefore = false;
this.allowAfter = false;
break;
}
};
Extend.next_id = 0;
Extend.prototype = new Node();
Extend.prototype.type = "Extend";
Extend.prototype.accept = function (visitor) {
this.selector = visitor.visit(this.selector);
};
Extend.prototype.eval = function (context) {
return new Extend(this.selector.eval(context), this.option, this.index, this.currentFileInfo, this.visibilityInfo());
};
Extend.prototype.clone = function (context) {
return new Extend(this.selector, this.option, this.index, this.currentFileInfo, this.visibilityInfo());
};
//it concatenates (joins) all selectors in selector array
Extend.prototype.findSelfSelectors = function (selectors) {
var selfElements = [],
i,
selectorElements;
for (i = 0; i < selectors.length; i++) {
selectorElements = selectors[i].elements;
// duplicate the logic in genCSS function inside the selector node.
// future TODO - move both logics into the selector joiner visitor
if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === "") {
selectorElements[0].combinator.value = ' ';
}
selfElements = selfElements.concat(selectors[i].elements);
}
this.selfSelectors = [new Selector(selfElements)];
this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo());
};
module.exports = Extend;

View File

@ -0,0 +1,166 @@
var Node = require("./node"),
Media = require("./media"),
URL = require("./url"),
Quoted = require("./quoted"),
Ruleset = require("./ruleset"),
Anonymous = require("./anonymous");
//
// CSS @import node
//
// The general strategy here is that we don't want to wait
// for the parsing to be completed, before we start importing
// the file. That's because in the context of a browser,
// most of the time will be spent waiting for the server to respond.
//
// On creation, we push the import path to our import queue, though
// `import,push`, we also pass it a callback, which it'll call once
// the file has been fetched, and parsed.
//
var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) {
this.options = options;
this.index = index;
this.path = path;
this.features = features;
this.currentFileInfo = currentFileInfo;
this.allowRoot = true;
if (this.options.less !== undefined || this.options.inline) {
this.css = !this.options.less || this.options.inline;
} else {
var pathValue = this.getPath();
if (pathValue && /[#\.\&\?\/]css([\?;].*)?$/.test(pathValue)) {
this.css = true;
}
}
this.copyVisibilityInfo(visibilityInfo);
};
//
// The actual import node doesn't return anything, when converted to CSS.
// The reason is that it's used at the evaluation stage, so that the rules
// it imports can be treated like any other rules.
//
// In `eval`, we make sure all Import nodes get evaluated, recursively, so
// we end up with a flat structure, which can easily be imported in the parent
// ruleset.
//
Import.prototype = new Node();
Import.prototype.type = "Import";
Import.prototype.accept = function (visitor) {
if (this.features) {
this.features = visitor.visit(this.features);
}
this.path = visitor.visit(this.path);
if (!this.options.plugin && !this.options.inline && this.root) {
this.root = visitor.visit(this.root);
}
};
Import.prototype.genCSS = function (context, output) {
if (this.css && this.path.currentFileInfo.reference === undefined) {
output.add("@import ", this.currentFileInfo, this.index);
this.path.genCSS(context, output);
if (this.features) {
output.add(" ");
this.features.genCSS(context, output);
}
output.add(';');
}
};
Import.prototype.getPath = function () {
return (this.path instanceof URL) ?
this.path.value.value : this.path.value;
};
Import.prototype.isVariableImport = function () {
var path = this.path;
if (path instanceof URL) {
path = path.value;
}
if (path instanceof Quoted) {
return path.containsVariables();
}
return true;
};
Import.prototype.evalForImport = function (context) {
var path = this.path;
if (path instanceof URL) {
path = path.value;
}
return new Import(path.eval(context), this.features, this.options, this.index, this.currentFileInfo, this.visibilityInfo());
};
Import.prototype.evalPath = function (context) {
var path = this.path.eval(context);
var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
if (!(path instanceof URL)) {
if (rootpath) {
var pathValue = path.value;
// Add the base path if the import is relative
if (pathValue && context.isPathRelative(pathValue)) {
path.value = rootpath + pathValue;
}
}
path.value = context.normalizePath(path.value);
}
return path;
};
Import.prototype.eval = function (context) {
var result = this.doEval(context);
if (this.options.reference || this.blocksVisibility()) {
if (result.length || result.length === 0) {
result.forEach(function (node) {
node.addVisibilityBlock();
}
);
} else {
result.addVisibilityBlock();
}
}
return result;
};
Import.prototype.doEval = function (context) {
var ruleset, registry,
features = this.features && this.features.eval(context);
if (this.options.plugin) {
registry = context.frames[0] && context.frames[0].functionRegistry;
if ( registry && this.root && this.root.functions ) {
registry.addMultiple( this.root.functions );
}
return [];
}
if (this.skip) {
if (typeof this.skip === "function") {
this.skip = this.skip();
}
if (this.skip) {
return [];
}
}
if (this.options.inline) {
var contents = new Anonymous(this.root, 0,
{
filename: this.importedFilename,
reference: this.path.currentFileInfo && this.path.currentFileInfo.reference
}, true, true);
return this.features ? new Media([contents], this.features.value) : [contents];
} else if (this.css) {
var newImport = new Import(this.evalPath(context), features, this.options, this.index);
if (!newImport.css && this.error) {
throw this.error;
}
return newImport;
} else {
ruleset = new Ruleset(null, this.root.rules.slice(0));
ruleset.evalImports(context);
return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
}
};
module.exports = Import;

View File

@ -0,0 +1,41 @@
var tree = {};
tree.Node = require('./node');
tree.Alpha = require('./alpha');
tree.Color = require('./color');
tree.Directive = require('./directive');
tree.DetachedRuleset = require('./detached-ruleset');
tree.Operation = require('./operation');
tree.Dimension = require('./dimension');
tree.Unit = require('./unit');
tree.Keyword = require('./keyword');
tree.Variable = require('./variable');
tree.Ruleset = require('./ruleset');
tree.Element = require('./element');
tree.Attribute = require('./attribute');
tree.Combinator = require('./combinator');
tree.Selector = require('./selector');
tree.Quoted = require('./quoted');
tree.Expression = require('./expression');
tree.Rule = require('./rule');
tree.Call = require('./call');
tree.URL = require('./url');
tree.Import = require('./import');
tree.mixin = {
Call: require('./mixin-call'),
Definition: require('./mixin-definition')
};
tree.Comment = require('./comment');
tree.Anonymous = require('./anonymous');
tree.Value = require('./value');
tree.JavaScript = require('./javascript');
tree.Assignment = require('./assignment');
tree.Condition = require('./condition');
tree.Paren = require('./paren');
tree.Media = require('./media');
tree.UnicodeDescriptor = require('./unicode-descriptor');
tree.Negative = require('./negative');
tree.Extend = require('./extend');
tree.RulesetCall = require('./ruleset-call');
module.exports = tree;

View File

@ -0,0 +1,28 @@
var JsEvalNode = require("./js-eval-node"),
Dimension = require("./dimension"),
Quoted = require("./quoted"),
Anonymous = require("./anonymous");
var JavaScript = function (string, escaped, index, currentFileInfo) {
this.escaped = escaped;
this.expression = string;
this.index = index;
this.currentFileInfo = currentFileInfo;
};
JavaScript.prototype = new JsEvalNode();
JavaScript.prototype.type = "JavaScript";
JavaScript.prototype.eval = function(context) {
var result = this.evaluateJavaScript(this.expression, context);
if (typeof result === 'number') {
return new Dimension(result);
} else if (typeof result === 'string') {
return new Quoted('"' + result + '"', result, this.escaped, this.index);
} else if (Array.isArray(result)) {
return new Anonymous(result.join(', '));
} else {
return new Anonymous(result);
}
};
module.exports = JavaScript;

View File

@ -0,0 +1,61 @@
var Node = require("./node"),
Variable = require("./variable");
var JsEvalNode = function() {
};
JsEvalNode.prototype = new Node();
JsEvalNode.prototype.evaluateJavaScript = function (expression, context) {
var result,
that = this,
evalContext = {};
if (context.javascriptEnabled !== undefined && !context.javascriptEnabled) {
throw { message: "You are using JavaScript, which has been disabled.",
filename: this.currentFileInfo.filename,
index: this.index };
}
expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
return that.jsify(new Variable('@' + name, that.index, that.currentFileInfo).eval(context));
});
try {
expression = new Function('return (' + expression + ')');
} catch (e) {
throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
filename: this.currentFileInfo.filename,
index: this.index };
}
var variables = context.frames[0].variables();
for (var k in variables) {
if (variables.hasOwnProperty(k)) {
/*jshint loopfunc:true */
evalContext[k.slice(1)] = {
value: variables[k].value,
toJS: function () {
return this.value.eval(context).toCSS();
}
};
}
}
try {
result = expression.call(evalContext);
} catch (e) {
throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message.replace(/["]/g, "'") + "'" ,
filename: this.currentFileInfo.filename,
index: this.index };
}
return result;
};
JsEvalNode.prototype.jsify = function (obj) {
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
} else {
return obj.toCSS();
}
};
module.exports = JsEvalNode;

View File

@ -0,0 +1,14 @@
var Node = require("./node");
var Keyword = function (value) { this.value = value; };
Keyword.prototype = new Node();
Keyword.prototype.type = "Keyword";
Keyword.prototype.genCSS = function (context, output) {
if (this.value === '%') { throw { type: "Syntax", message: "Invalid % without number" }; }
output.add(this.value);
};
Keyword.True = new Keyword('true');
Keyword.False = new Keyword('false');
module.exports = Keyword;

View File

@ -0,0 +1,145 @@
var Ruleset = require("./ruleset"),
Value = require("./value"),
Selector = require("./selector"),
Anonymous = require("./anonymous"),
Expression = require("./expression"),
Directive = require("./directive");
var Media = function (value, features, index, currentFileInfo, visibilityInfo) {
this.index = index;
this.currentFileInfo = currentFileInfo;
var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
this.features = new Value(features);
this.rules = [new Ruleset(selectors, value)];
this.rules[0].allowImports = true;
this.copyVisibilityInfo(visibilityInfo);
this.allowRoot = true;
};
Media.prototype = new Directive();
Media.prototype.type = "Media";
Media.prototype.isRulesetLike = true;
Media.prototype.accept = function (visitor) {
if (this.features) {
this.features = visitor.visit(this.features);
}
if (this.rules) {
this.rules = visitor.visitArray(this.rules);
}
};
Media.prototype.genCSS = function (context, output) {
output.add('@media ', this.currentFileInfo, this.index);
this.features.genCSS(context, output);
this.outputRuleset(context, output, this.rules);
};
Media.prototype.eval = function (context) {
if (!context.mediaBlocks) {
context.mediaBlocks = [];
context.mediaPath = [];
}
var media = new Media(null, [], this.index, this.currentFileInfo, this.visibilityInfo());
if (this.debugInfo) {
this.rules[0].debugInfo = this.debugInfo;
media.debugInfo = this.debugInfo;
}
var strictMathBypass = false;
if (!context.strictMath) {
strictMathBypass = true;
context.strictMath = true;
}
try {
media.features = this.features.eval(context);
}
finally {
if (strictMathBypass) {
context.strictMath = false;
}
}
context.mediaPath.push(media);
context.mediaBlocks.push(media);
this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
context.frames.unshift(this.rules[0]);
media.rules = [this.rules[0].eval(context)];
context.frames.shift();
context.mediaPath.pop();
return context.mediaPath.length === 0 ? media.evalTop(context) :
media.evalNested(context);
};
Media.prototype.evalTop = function (context) {
var result = this;
// Render all dependent Media blocks.
if (context.mediaBlocks.length > 1) {
var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
result = new Ruleset(selectors, context.mediaBlocks);
result.multiMedia = true;
result.copyVisibilityInfo(this.visibilityInfo());
}
delete context.mediaBlocks;
delete context.mediaPath;
return result;
};
Media.prototype.evalNested = function (context) {
var i, value,
path = context.mediaPath.concat([this]);
// Extract the media-query conditions separated with `,` (OR).
for (i = 0; i < path.length; i++) {
value = path[i].features instanceof Value ?
path[i].features.value : path[i].features;
path[i] = Array.isArray(value) ? value : [value];
}
// Trace all permutations to generate the resulting media-query.
//
// (a, b and c) with nested (d, e) ->
// a and d
// a and e
// b and c and d
// b and c and e
this.features = new Value(this.permute(path).map(function (path) {
path = path.map(function (fragment) {
return fragment.toCSS ? fragment : new Anonymous(fragment);
});
for (i = path.length - 1; i > 0; i--) {
path.splice(i, 0, new Anonymous("and"));
}
return new Expression(path);
}));
// Fake a tree-node that doesn't output anything.
return new Ruleset([], []);
};
Media.prototype.permute = function (arr) {
if (arr.length === 0) {
return [];
} else if (arr.length === 1) {
return arr[0];
} else {
var result = [];
var rest = this.permute(arr.slice(1));
for (var i = 0; i < rest.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
result.push([arr[0][j]].concat(rest[i]));
}
}
return result;
}
};
Media.prototype.bubbleSelectors = function (selectors) {
if (!selectors) {
return;
}
this.rules = [new Ruleset(selectors.slice(0), [this.rules[0]])];
};
module.exports = Media;

View File

@ -0,0 +1,183 @@
var Node = require("./node"),
Selector = require("./selector"),
MixinDefinition = require("./mixin-definition"),
defaultFunc = require("../functions/default");
var MixinCall = function (elements, args, index, currentFileInfo, important) {
this.selector = new Selector(elements);
this.arguments = args || [];
this.index = index;
this.currentFileInfo = currentFileInfo;
this.important = important;
this.allowRoot = true;
};
MixinCall.prototype = new Node();
MixinCall.prototype.type = "MixinCall";
MixinCall.prototype.accept = function (visitor) {
if (this.selector) {
this.selector = visitor.visit(this.selector);
}
if (this.arguments.length) {
this.arguments = visitor.visitArray(this.arguments);
}
};
MixinCall.prototype.eval = function (context) {
var mixins, mixin, mixinPath, args = [], arg, argValue,
rules = [], match = false, i, m, f, isRecursive, isOneFound,
candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1,
defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter;
function calcDefGroup(mixin, mixinPath) {
var f, p, namespace;
for (f = 0; f < 2; f++) {
conditionResult[f] = true;
defaultFunc.value(f);
for (p = 0; p < mixinPath.length && conditionResult[f]; p++) {
namespace = mixinPath[p];
if (namespace.matchCondition) {
conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context);
}
}
if (mixin.matchCondition) {
conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context);
}
}
if (conditionResult[0] || conditionResult[1]) {
if (conditionResult[0] != conditionResult[1]) {
return conditionResult[1] ?
defTrue : defFalse;
}
return defNone;
}
return defFalseEitherCase;
}
for (i = 0; i < this.arguments.length; i++) {
arg = this.arguments[i];
argValue = arg.value.eval(context);
if (arg.expand && Array.isArray(argValue.value)) {
argValue = argValue.value;
for (m = 0; m < argValue.length; m++) {
args.push({value: argValue[m]});
}
} else {
args.push({name: arg.name, value: argValue});
}
}
noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);};
for (i = 0; i < context.frames.length; i++) {
if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) {
isOneFound = true;
// To make `default()` function independent of definition order we have two "subpasses" here.
// At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
// and build candidate list with corresponding flags. Then, when we know all possible matches,
// we make a final decision.
for (m = 0; m < mixins.length; m++) {
mixin = mixins[m].rule;
mixinPath = mixins[m].path;
isRecursive = false;
for (f = 0; f < context.frames.length; f++) {
if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) {
isRecursive = true;
break;
}
}
if (isRecursive) {
continue;
}
if (mixin.matchArgs(args, context)) {
candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)};
if (candidate.group !== defFalseEitherCase) {
candidates.push(candidate);
}
match = true;
}
}
defaultFunc.reset();
count = [0, 0, 0];
for (m = 0; m < candidates.length; m++) {
count[candidates[m].group]++;
}
if (count[defNone] > 0) {
defaultResult = defFalse;
} else {
defaultResult = defTrue;
if ((count[defTrue] + count[defFalse]) > 1) {
throw { type: 'Runtime',
message: 'Ambiguous use of `default()` found when matching for `' + this.format(args) + '`',
index: this.index, filename: this.currentFileInfo.filename };
}
}
for (m = 0; m < candidates.length; m++) {
candidate = candidates[m].group;
if ((candidate === defNone) || (candidate === defaultResult)) {
try {
mixin = candidates[m].mixin;
if (!(mixin instanceof MixinDefinition)) {
originalRuleset = mixin.originalRuleset || mixin;
mixin = new MixinDefinition("", [], mixin.rules, null, false, null, originalRuleset.visibilityInfo());
mixin.originalRuleset = originalRuleset;
}
var newRules = mixin.evalCall(context, args, this.important).rules;
this._setVisibilityToReplacement(newRules);
Array.prototype.push.apply(rules, newRules);
} catch (e) {
throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
}
}
}
if (match) {
return rules;
}
}
}
if (isOneFound) {
throw { type: 'Runtime',
message: 'No matching definition was found for `' + this.format(args) + '`',
index: this.index, filename: this.currentFileInfo.filename };
} else {
throw { type: 'Name',
message: this.selector.toCSS().trim() + " is undefined",
index: this.index, filename: this.currentFileInfo.filename };
}
};
MixinCall.prototype._setVisibilityToReplacement = function (replacement) {
var i, rule;
if (this.blocksVisibility()) {
for (i = 0; i < replacement.length; i++) {
rule = replacement[i];
rule.addVisibilityBlock();
}
}
};
MixinCall.prototype.format = function (args) {
return this.selector.toCSS().trim() + '(' +
(args ? args.map(function (a) {
var argValue = "";
if (a.name) {
argValue += a.name + ":";
}
if (a.value.toCSS) {
argValue += a.value.toCSS();
} else {
argValue += "???";
}
return argValue;
}).join(', ') : "") + ")";
};
module.exports = MixinCall;

View File

@ -0,0 +1,201 @@
var Selector = require("./selector"),
Element = require("./element"),
Ruleset = require("./ruleset"),
Rule = require("./rule"),
Expression = require("./expression"),
contexts = require("../contexts");
var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) {
this.name = name;
this.selectors = [new Selector([new Element(null, name, this.index, this.currentFileInfo)])];
this.params = params;
this.condition = condition;
this.variadic = variadic;
this.arity = params.length;
this.rules = rules;
this._lookups = {};
var optionalParameters = [];
this.required = params.reduce(function (count, p) {
if (!p.name || (p.name && !p.value)) {
return count + 1;
}
else {
optionalParameters.push(p.name);
return count;
}
}, 0);
this.optionalParameters = optionalParameters;
this.frames = frames;
this.copyVisibilityInfo(visibilityInfo);
this.allowRoot = true;
};
Definition.prototype = new Ruleset();
Definition.prototype.type = "MixinDefinition";
Definition.prototype.evalFirst = true;
Definition.prototype.accept = function (visitor) {
if (this.params && this.params.length) {
this.params = visitor.visitArray(this.params);
}
this.rules = visitor.visitArray(this.rules);
if (this.condition) {
this.condition = visitor.visit(this.condition);
}
};
Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) {
/*jshint boss:true */
var frame = new Ruleset(null, null),
varargs, arg,
params = this.params.slice(0),
i, j, val, name, isNamedFound, argIndex, argsLength = 0;
if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {
frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();
}
mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames));
if (args) {
args = args.slice(0);
argsLength = args.length;
for (i = 0; i < argsLength; i++) {
arg = args[i];
if (name = (arg && arg.name)) {
isNamedFound = false;
for (j = 0; j < params.length; j++) {
if (!evaldArguments[j] && name === params[j].name) {
evaldArguments[j] = arg.value.eval(context);
frame.prependRule(new Rule(name, arg.value.eval(context)));
isNamedFound = true;
break;
}
}
if (isNamedFound) {
args.splice(i, 1);
i--;
continue;
} else {
throw { type: 'Runtime', message: "Named argument for " + this.name +
' ' + args[i].name + ' not found' };
}
}
}
}
argIndex = 0;
for (i = 0; i < params.length; i++) {
if (evaldArguments[i]) { continue; }
arg = args && args[argIndex];
if (name = params[i].name) {
if (params[i].variadic) {
varargs = [];
for (j = argIndex; j < argsLength; j++) {
varargs.push(args[j].value.eval(context));
}
frame.prependRule(new Rule(name, new Expression(varargs).eval(context)));
} else {
val = arg && arg.value;
if (val) {
val = val.eval(context);
} else if (params[i].value) {
val = params[i].value.eval(mixinEnv);
frame.resetCache();
} else {
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
' (' + argsLength + ' for ' + this.arity + ')' };
}
frame.prependRule(new Rule(name, val));
evaldArguments[i] = val;
}
}
if (params[i].variadic && args) {
for (j = argIndex; j < argsLength; j++) {
evaldArguments[j] = args[j].value.eval(context);
}
}
argIndex++;
}
return frame;
};
Definition.prototype.makeImportant = function() {
var rules = !this.rules ? this.rules : this.rules.map(function (r) {
if (r.makeImportant) {
return r.makeImportant(true);
} else {
return r;
}
});
var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);
return result;
};
Definition.prototype.eval = function (context) {
return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || context.frames.slice(0));
};
Definition.prototype.evalCall = function (context, args, important) {
var _arguments = [],
mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames,
frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments),
rules, ruleset;
frame.prependRule(new Rule('@arguments', new Expression(_arguments).eval(context)));
rules = this.rules.slice(0);
ruleset = new Ruleset(null, rules);
ruleset.originalRuleset = this;
ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames)));
if (important) {
ruleset = ruleset.makeImportant();
}
return ruleset;
};
Definition.prototype.matchCondition = function (args, context) {
if (this.condition && !this.condition.eval(
new contexts.Eval(context,
[this.evalParams(context, /* the parameter variables*/
new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
.concat(this.frames || []) // the parent namespace/mixin frames
.concat(context.frames)))) { // the current environment frames
return false;
}
return true;
};
Definition.prototype.matchArgs = function (args, context) {
var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters;
var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) {
if (optionalParameters.indexOf(p.name) < 0) {
return count + 1;
} else {
return count;
}
}, 0);
if (! this.variadic) {
if (requiredArgsCnt < this.required) {
return false;
}
if (allArgsCnt > this.params.length) {
return false;
}
} else {
if (requiredArgsCnt < (this.required - 1)) {
return false;
}
}
// check patterns
len = Math.min(requiredArgsCnt, this.arity);
for (var i = 0; i < len; i++) {
if (!this.params[i].name && !this.params[i].variadic) {
if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) {
return false;
}
}
}
return true;
};
module.exports = Definition;

View File

@ -0,0 +1,20 @@
var Node = require("./node"),
Operation = require("./operation"),
Dimension = require("./dimension");
var Negative = function (node) {
this.value = node;
};
Negative.prototype = new Node();
Negative.prototype.type = "Negative";
Negative.prototype.genCSS = function (context, output) {
output.add('-');
this.value.genCSS(context, output);
};
Negative.prototype.eval = function (context) {
if (context.isMathOn()) {
return (new Operation('*', [new Dimension(-1), this.value])).eval(context);
}
return new Negative(this.value.eval(context));
};
module.exports = Negative;

View File

@ -0,0 +1,123 @@
var Node = function() {
};
Node.prototype.toCSS = function (context) {
var strs = [];
this.genCSS(context, {
add: function(chunk, fileInfo, index) {
strs.push(chunk);
},
isEmpty: function () {
return strs.length === 0;
}
});
return strs.join('');
};
Node.prototype.genCSS = function (context, output) {
output.add(this.value);
};
Node.prototype.accept = function (visitor) {
this.value = visitor.visit(this.value);
};
Node.prototype.eval = function () { return this; };
Node.prototype._operate = function (context, op, a, b) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
};
Node.prototype.fround = function(context, value) {
var precision = context && context.numPrecision;
//add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999....) are properly rounded...
return (precision == null) ? value : Number((value + 2e-16).toFixed(precision));
};
Node.compare = function (a, b) {
/* returns:
-1: a < b
0: a = b
1: a > b
and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */
if ((a.compare) &&
// for "symmetric results" force toCSS-based comparison
// of Quoted or Anonymous if either value is one of those
!(b.type === "Quoted" || b.type === "Anonymous")) {
return a.compare(b);
} else if (b.compare) {
return -b.compare(a);
} else if (a.type !== b.type) {
return undefined;
}
a = a.value;
b = b.value;
if (!Array.isArray(a)) {
return a === b ? 0 : undefined;
}
if (a.length !== b.length) {
return undefined;
}
for (var i = 0; i < a.length; i++) {
if (Node.compare(a[i], b[i]) !== 0) {
return undefined;
}
}
return 0;
};
Node.numericCompare = function (a, b) {
return a < b ? -1
: a === b ? 0
: a > b ? 1 : undefined;
};
// Returns true if this node represents root of ast imported by reference
Node.prototype.blocksVisibility = function () {
if (this.visibilityBlocks == null) {
this.visibilityBlocks = 0;
}
return this.visibilityBlocks !== 0;
};
Node.prototype.addVisibilityBlock = function () {
if (this.visibilityBlocks == null) {
this.visibilityBlocks = 0;
}
this.visibilityBlocks = this.visibilityBlocks + 1;
};
Node.prototype.removeVisibilityBlock = function () {
if (this.visibilityBlocks == null) {
this.visibilityBlocks = 0;
}
this.visibilityBlocks = this.visibilityBlocks - 1;
};
//Turns on node visibility - if called node will be shown in output regardless
//of whether it comes from import by reference or not
Node.prototype.ensureVisibility = function () {
this.nodeVisible = true;
};
//Turns off node visibility - if called node will NOT be shown in output regardless
//of whether it comes from import by reference or not
Node.prototype.ensureInvisibility = function () {
this.nodeVisible = false;
};
// return values:
// false - the node must not be visible
// true - the node must be visible
// undefined or null - the node has the same visibility as its parent
Node.prototype.isVisible = function () {
return this.nodeVisible;
};
Node.prototype.visibilityInfo = function() {
return {
visibilityBlocks: this.visibilityBlocks,
nodeVisible: this.nodeVisible
};
};
Node.prototype.copyVisibilityInfo = function(info) {
if (!info) {
return;
}
this.visibilityBlocks = info.visibilityBlocks;
this.nodeVisible = info.nodeVisible;
};
module.exports = Node;

View File

@ -0,0 +1,48 @@
var Node = require("./node"),
Color = require("./color"),
Dimension = require("./dimension");
var Operation = function (op, operands, isSpaced) {
this.op = op.trim();
this.operands = operands;
this.isSpaced = isSpaced;
};
Operation.prototype = new Node();
Operation.prototype.type = "Operation";
Operation.prototype.accept = function (visitor) {
this.operands = visitor.visit(this.operands);
};
Operation.prototype.eval = function (context) {
var a = this.operands[0].eval(context),
b = this.operands[1].eval(context);
if (context.isMathOn()) {
if (a instanceof Dimension && b instanceof Color) {
a = a.toColor();
}
if (b instanceof Dimension && a instanceof Color) {
b = b.toColor();
}
if (!a.operate) {
throw { type: "Operation",
message: "Operation on an invalid type" };
}
return a.operate(context, this.op, b);
} else {
return new Operation(this.op, [a, b], this.isSpaced);
}
};
Operation.prototype.genCSS = function (context, output) {
this.operands[0].genCSS(context, output);
if (this.isSpaced) {
output.add(" ");
}
output.add(this.op);
if (this.isSpaced) {
output.add(" ");
}
this.operands[1].genCSS(context, output);
};
module.exports = Operation;

View File

@ -0,0 +1,16 @@
var Node = require("./node");
var Paren = function (node) {
this.value = node;
};
Paren.prototype = new Node();
Paren.prototype.type = "Paren";
Paren.prototype.genCSS = function (context, output) {
output.add('(');
this.value.genCSS(context, output);
output.add(')');
};
Paren.prototype.eval = function (context) {
return new Paren(this.value.eval(context));
};
module.exports = Paren;

View File

@ -0,0 +1,55 @@
var Node = require("./node"),
JsEvalNode = require("./js-eval-node"),
Variable = require("./variable");
var Quoted = function (str, content, escaped, index, currentFileInfo) {
this.escaped = (escaped == null) ? true : escaped;
this.value = content || '';
this.quote = str.charAt(0);
this.index = index;
this.currentFileInfo = currentFileInfo;
};
Quoted.prototype = new JsEvalNode();
Quoted.prototype.type = "Quoted";
Quoted.prototype.genCSS = function (context, output) {
if (!this.escaped) {
output.add(this.quote, this.currentFileInfo, this.index);
}
output.add(this.value);
if (!this.escaped) {
output.add(this.quote);
}
};
Quoted.prototype.containsVariables = function() {
return this.value.match(/(`([^`]+)`)|@\{([\w-]+)\}/);
};
Quoted.prototype.eval = function (context) {
var that = this, value = this.value;
var javascriptReplacement = function (_, exp) {
return String(that.evaluateJavaScript(exp, context));
};
var interpolationReplacement = function (_, name) {
var v = new Variable('@' + name, that.index, that.currentFileInfo).eval(context, true);
return (v instanceof Quoted) ? v.value : v.toCSS();
};
function iterativeReplace(value, regexp, replacementFnc) {
var evaluatedValue = value;
do {
value = evaluatedValue;
evaluatedValue = value.replace(regexp, replacementFnc);
} while (value !== evaluatedValue);
return evaluatedValue;
}
value = iterativeReplace(value, /`([^`]+)`/g, javascriptReplacement);
value = iterativeReplace(value, /@\{([\w-]+)\}/g, interpolationReplacement);
return new Quoted(this.quote + value + this.quote, value, this.escaped, this.index, this.currentFileInfo);
};
Quoted.prototype.compare = function (other) {
// when comparing quoted strings allow the quote to differ
if (other.type === "Quoted" && !this.escaped && !other.escaped) {
return Node.numericCompare(this.value, other.value);
} else {
return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
}
};
module.exports = Quoted;

View File

@ -0,0 +1,96 @@
var Node = require("./node"),
Value = require("./value"),
Keyword = require("./keyword");
var Rule = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
this.name = name;
this.value = (value instanceof Node) ? value : new Value([value]); //value instanceof tree.Value || value instanceof tree.Ruleset ??
this.important = important ? ' ' + important.trim() : '';
this.merge = merge;
this.index = index;
this.currentFileInfo = currentFileInfo;
this.inline = inline || false;
this.variable = (variable !== undefined) ? variable
: (name.charAt && (name.charAt(0) === '@'));
this.allowRoot = true;
};
function evalName(context, name) {
var value = "", i, n = name.length,
output = {add: function (s) {value += s;}};
for (i = 0; i < n; i++) {
name[i].eval(context).genCSS(context, output);
}
return value;
}
Rule.prototype = new Node();
Rule.prototype.type = "Rule";
Rule.prototype.genCSS = function (context, output) {
output.add(this.name + (context.compress ? ':' : ': '), this.currentFileInfo, this.index);
try {
this.value.genCSS(context, output);
}
catch(e) {
e.index = this.index;
e.filename = this.currentFileInfo.filename;
throw e;
}
output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? "" : ";"), this.currentFileInfo, this.index);
};
Rule.prototype.eval = function (context) {
var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable;
if (typeof name !== "string") {
// expand 'primitive' name directly to get
// things faster (~10% for benchmark.less):
name = (name.length === 1) && (name[0] instanceof Keyword) ?
name[0].value : evalName(context, name);
variable = false; // never treat expanded interpolation as new variable name
}
if (name === "font" && !context.strictMath) {
strictMathBypass = true;
context.strictMath = true;
}
try {
context.importantScope.push({});
evaldValue = this.value.eval(context);
if (!this.variable && evaldValue.type === "DetachedRuleset") {
throw { message: "Rulesets cannot be evaluated on a property.",
index: this.index, filename: this.currentFileInfo.filename };
}
var important = this.important,
importantResult = context.importantScope.pop();
if (!important && importantResult.important) {
important = importantResult.important;
}
return new Rule(name,
evaldValue,
important,
this.merge,
this.index, this.currentFileInfo, this.inline,
variable);
}
catch(e) {
if (typeof e.index !== 'number') {
e.index = this.index;
e.filename = this.currentFileInfo.filename;
}
throw e;
}
finally {
if (strictMathBypass) {
context.strictMath = false;
}
}
};
Rule.prototype.makeImportant = function () {
return new Rule(this.name,
this.value,
"!important",
this.merge,
this.index, this.currentFileInfo, this.inline);
};
module.exports = Rule;

Some files were not shown because too many files have changed in this diff Show More