Comparing version 0.9.2 to 0.9.3
## Changelog | ||
## 0.9.3 | ||
* Allows `text-face-name` properties to be unquoted | ||
* Detects inline Format XML tags in `text-name` and passes such output | ||
straight to XML for advanced text names. | ||
* Fixes bugs around concatenation of strings in expressions | ||
* Fixes parsing of comments in between selectors | ||
* Fixes parsing of whitespace in calls | ||
* Improved error messages for unknown properties - advises user on | ||
the property name most closely matching the incorrect input. | ||
* Improved errors for calls, advises user on number of arguments | ||
* Fixes instance inheritance - thanks @gravitystorm! | ||
## 0.9.2 | ||
@@ -4,0 +17,0 @@ |
@@ -41,3 +41,3 @@ var util = require('util'); | ||
message = options.indent + message + stylize(ctx.message, 'red'); | ||
ctx.filename && (message += stylize(' in ', 'red') + ctx.filename); | ||
if (ctx.filename) (message += stylize(' in ', 'red') + ctx.filename); | ||
@@ -55,3 +55,3 @@ util.error(message, error); | ||
[ 'call', 'color', 'comment', 'definition', 'dimension', | ||
'directive', 'element', 'expression', 'filterset', 'filter', 'field', | ||
'element', 'expression', 'filterset', 'filter', 'field', | ||
'keyword', 'layer', 'literal', 'operation', 'quoted', 'imagefilter', | ||
@@ -58,0 +58,0 @@ 'reference', 'rule', 'ruleset', 'selector', 'style', 'url', 'value', |
@@ -276,7 +276,15 @@ var carto, tree, _; | ||
if (level > 0) { | ||
// TODO: make invalid instead | ||
throw makeError({ | ||
message: 'Missing closing `}`', | ||
index: i | ||
}); | ||
if (inString) { | ||
// TODO: make invalid instead | ||
throw makeError({ | ||
message: 'Missing closing ' + inString, | ||
index: i | ||
}); | ||
} else { | ||
// TODO: make invalid instead | ||
throw makeError({ | ||
message: 'Missing closing `}`', | ||
index: i | ||
}); | ||
} | ||
} | ||
@@ -465,3 +473,3 @@ | ||
if (! (name = /^([\w\-]+|%)\(/.exec(chunks[j]))) return; | ||
if (!(name = /^([\w\-]+|%)\(/.exec(chunks[j]))) return; | ||
@@ -473,5 +481,7 @@ name = name[1]; | ||
} else { | ||
i += name.length + 1; | ||
i += name.length; | ||
} | ||
$('('); // Parse the '(' and consume whitespace. | ||
args = $(this.entities.arguments); | ||
@@ -694,3 +704,5 @@ | ||
selectors.push(s); | ||
$(this.comment); | ||
if (! $(',')) { break; } | ||
$(this.comment); | ||
} | ||
@@ -697,0 +709,0 @@ if (s) $(this.comment); |
(function(tree) { | ||
var _ = require('underscore'); | ||
@@ -24,3 +25,3 @@ tree.Call = function Call(name, args, index) { | ||
// | ||
eval: function(env) { | ||
'eval': function(env) { | ||
var args = this.args.map(function(a) { return a.eval(env); }); | ||
@@ -56,4 +57,13 @@ | ||
if (!fn) { | ||
var functions = tree.Reference.mapnikFunctions(); | ||
// cheap closest, needs improvement. | ||
var name = this.name; | ||
var mean = functions.map(function(f) { | ||
return [f[0], tree.Reference.editDistance(name, f[0]), f[1]]; | ||
}).sort(function(a, b) { | ||
return a[1] - b[1]; | ||
}); | ||
env.error({ | ||
message: 'unknown function ' + this.name, | ||
message: 'unknown function ' + this.name + '(), did you mean ' + | ||
mean[0][0] + '(' + mean[0][2] + ')', | ||
index: this.index, | ||
@@ -70,3 +80,3 @@ type: 'runtime', | ||
env.error({ | ||
message: 'function ' + this.name + ' takes ' + | ||
message: 'function ' + this.name + '() takes ' + | ||
fn[1] + ' arguments and was given ' + args.length, | ||
@@ -73,0 +83,0 @@ index: this.index, |
@@ -132,3 +132,7 @@ (function(tree) { | ||
} else { | ||
xml += '><![CDATA[' + tagcontent + ']]></' + name + '>\n'; | ||
if (tagcontent.indexOf('<Format') != -1) { | ||
xml += '>' + tagcontent + '</' + name + '>\n'; | ||
} else { | ||
xml += '><![CDATA[' + tagcontent + ']]></' + name + '>\n'; | ||
} | ||
} | ||
@@ -135,0 +139,0 @@ } |
@@ -19,4 +19,3 @@ (function(tree) { | ||
operate: function(op, other) { | ||
return new tree.Quoted(true, | ||
tree.operate(op, this.toString(), other.toString(this.contains_field))); | ||
return new tree.Quoted(tree.operate(op, this.toString(), other.toString(this.contains_field))); | ||
} | ||
@@ -23,0 +22,0 @@ }; |
@@ -79,3 +79,3 @@ /* | ||
*/ | ||
tree.Reference.mapnikFunction = function(name) { | ||
tree.Reference.mapnikFunctions = function() { | ||
var functions = []; | ||
@@ -89,3 +89,11 @@ for (var i in tree.Reference.data.symbolizers) { | ||
} | ||
return _.find(functions, function(f) { | ||
return functions; | ||
}; | ||
/* | ||
* For transform properties and image-filters, | ||
* mapnik has its own functions. | ||
*/ | ||
tree.Reference.mapnikFunction = function(name) { | ||
return _.find(this.mapnikFunctions(), function(f) { | ||
return f[0] === name; | ||
@@ -135,2 +143,27 @@ }); | ||
// https://gist.github.com/982927 | ||
tree.Reference.editDistance = function(a, b){ | ||
if (a.length === 0) return b.length; | ||
if (b.length === 0) return a.length; | ||
var matrix = []; | ||
for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; } | ||
for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; } | ||
for (i = 1; i <= b.length; i++) { | ||
for (j = 1; j <= a.length; j++) { | ||
if (b.charAt(i-1) == a.charAt(j-1)) { | ||
matrix[i][j] = matrix[i-1][j-1]; | ||
} else { | ||
matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution | ||
Math.min(matrix[i][j-1] + 1, // insertion | ||
matrix[i-1][j] + 1)); // deletion | ||
} | ||
} | ||
} | ||
return matrix[b.length][a.length]; | ||
}; | ||
tree.Reference.validValue = function(env, selector, value) { | ||
@@ -142,5 +175,13 @@ var i, j; | ||
} else if (value.value[0].is == 'keyword') { | ||
return tree.Reference | ||
.selector(selector).type | ||
.indexOf(value.value[0].value) !== -1; | ||
if (typeof tree.Reference.selector(selector).type === 'object') { | ||
return tree.Reference | ||
.selector(selector).type | ||
.indexOf(value.value[0].value) !== -1; | ||
// Lax permissions for single strings. If you provide a keyword | ||
// aka unquoted string to a property that is a string, it'll be fine. | ||
} else if (tree.Reference.selector(selector).type === 'string') { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} else if (value.value[0].is == 'undefined') { | ||
@@ -147,0 +188,0 @@ // caught earlier in the chain - ignore here so that |
@@ -29,3 +29,3 @@ (function(tree) { | ||
tree.Rule.prototype.updateID = function() { | ||
return this.id = this.zoom + '#' + this.name; | ||
return this.id = this.zoom + '#' + this.instance + '#' + this.name; | ||
}; | ||
@@ -43,4 +43,14 @@ | ||
if (!tree.Reference.validSelector(this.name)) { | ||
var name = this.name; | ||
var mean = tree.Reference.selectors.map(function(f) { | ||
return [f, tree.Reference.editDistance(name, f)]; | ||
}).sort(function(a, b) { | ||
return a[1] - b[1]; | ||
}); | ||
var mean_message = ''; | ||
if (mean[0][1] < 3) { | ||
mean_message = '. Did you mean ' + mean[0][0] + '?'; | ||
} | ||
return env.error({ | ||
message: "Unrecognized rule: " + this.name, | ||
message: "Unrecognized rule: " + this.name + mean_message, | ||
index: this.index, | ||
@@ -63,9 +73,16 @@ type: 'syntax', | ||
} else { | ||
var typename; | ||
if (tree.Reference.selector(this.name).validate) { | ||
typename = tree.Reference.selector(this.name).validate; | ||
} else if (typeof tree.Reference.selector(this.name).type === 'object') { | ||
typename = 'keyword (options: ' + tree.Reference.selector(this.name).type.join(', ') + ')'; | ||
} else { | ||
typename = tree.Reference.selector(this.name).type; | ||
} | ||
return env.error({ | ||
message: 'Invalid value for ' + | ||
this.name + | ||
', a valid ' + | ||
(tree.Reference.selector(this.name).validate || | ||
tree.Reference.selector(this.name).type) + | ||
', the type ' + typename + | ||
' is expected. ' + this.value + | ||
' (of type ' + this.value.value[0].is + ') ' + | ||
' was given.', | ||
@@ -72,0 +89,0 @@ index: this.index, |
@@ -56,10 +56,2 @@ (function(tree) { | ||
}, | ||
/** | ||
* Extend this rule by adding rules from another ruleset | ||
* | ||
* Currently this is designed to accept less specific | ||
* rules and add their values only if this ruleset doesn't | ||
* contain them. | ||
*/ | ||
rulesets: function() { | ||
@@ -66,0 +58,0 @@ if (this._rulesets) { return this._rulesets; } |
{ | ||
"name": "carto", | ||
"version": "0.9.2", | ||
"version": "0.9.3", | ||
"description": "Mapnik Stylesheet Compiler", | ||
@@ -5,0 +5,0 @@ "url": "https://github.com/mapbox/carto", |
@@ -23,3 +23,3 @@ # CartoCSS | ||
carto.js MML: | ||
CartoCSS MML: | ||
@@ -43,9 +43,7 @@ { | ||
<pre><Stylesheet><![CDATA[ | ||
Map | ||
{ | ||
Map { | ||
map-bgcolor: #69f; | ||
} | ||
Layer | ||
{ | ||
Layer { | ||
line-width: 1; | ||
@@ -67,5 +65,5 @@ line-color: #696; | ||
In CSS, a certain object can only have one instance of a property. A `<div>` has a specific border width and color, rules that match better than others (#id instead of .class) override previous definitions. `carto.js` acts the same way normally for the sake of familiarity and organization, but Mapnik itself is more powerful. | ||
In CSS, a certain object can only have one instance of a property. A `<div>` has a specific border width and color, rules that match better than others (#id instead of .class) override previous definitions. `CartoCSS` acts the same way normally for the sake of familiarity and organization, but Mapnik itself is more powerful. | ||
Layers in Mapnik can have multiple [borders](http://trac.mapnik.org/wiki/LineSymbolizer) and multiple copies of other attributes. This ability is useful in drawing line outlines, like in the case of road borders or 'glow' effects around coasts. `carto.js` makes this accessible by allowing attachments to styles: | ||
Layers in Mapnik can have multiple [borders](http://trac.mapnik.org/wiki/LineSymbolizer) and multiple copies of other attributes. This ability is useful in drawing line outlines, like in the case of road borders or 'glow' effects around coasts. `CartoCSS` makes this accessible by allowing attachments to styles: | ||
@@ -82,3 +80,3 @@ #world { | ||
Attachments are optional: if you don't define them, carto.js does overriding of styles just like Cascadenik. | ||
Attachments are optional: if you don't define them, CartoCSS does overriding of styles just like Cascadenik. | ||
@@ -106,3 +104,3 @@ This brings us to another _incompatibility_: `line-inline` and `line-outline` have been removed from the language, because attachments are capable of the same trick. | ||
<th>cascadenik</th> | ||
<th>carto.js</th> | ||
<th>CartoCSS</th> | ||
</tr> | ||
@@ -129,3 +127,3 @@ <tr> | ||
`carto.js` is only compatible with [Mapnik2](http://trac.mapnik.org/wiki/Mapnik2). Compatibility with Mapnik 0.7.x is not planned. | ||
CartoCSS is only compatible with [Mapnik2](http://trac.mapnik.org/wiki/Mapnik2). Compatibility with Mapnik 0.7.x is not planned. | ||
@@ -135,5 +133,5 @@ ## Rasters and Buildings | ||
Rasters are supported in carto.js - it knows how to download `.vrt`, `.tiff`, and soon other raster formats, and the properties of the [RasterSymbolizer](http://trac.mapnik.org/wiki/RasterSymbolizer) are exposed in the language. | ||
Rasters are supported in CartoCSS - it knows how to download `.vrt`, `.tiff`, and soon other raster formats, and the properties of the [RasterSymbolizer](http://trac.mapnik.org/wiki/RasterSymbolizer) are exposed in the language. | ||
The [BuildingSymbolizer](http://trac.mapnik.org/wiki/BuildingSymbolizer) is also supported in `carto.js`. The code stores symbolizer types and properties in a JSON file (in `tree/reference.json`), so new Mapnik features can be quickly implemented here. | ||
The [BuildingSymbolizer](http://trac.mapnik.org/wiki/BuildingSymbolizer) is also supported in `CartoCSS`. The code stores symbolizer types and properties in a JSON file (in `tree/reference.json`), so new Mapnik features can be quickly implemented here. | ||
@@ -143,3 +141,3 @@ ## Variables & Expressions | ||
`carto.js` inherits from its basis in [less.js](http://lesscss.org/) some new features in CSS. One can define variables in stylesheets, and use expressions to modify them. | ||
CartoCSS inherits from its basis in [less.js](http://lesscss.org/) some new features in CSS. One can define variables in stylesheets, and use expressions to modify them. | ||
@@ -160,3 +158,3 @@ @mybackground: #2B4D2D; | ||
`carto.js` also inherits nesting of rules from less.js. | ||
CartoCSS also inherits nesting of rules from less.js. | ||
@@ -188,5 +186,6 @@ /* Applies to all layers with .land class */ | ||
## FontSets | ||
_new_ | ||
By defining multiple fonts in a `text-face-name` definition, you create [FontSets](http://trac.mapnik.org/wiki/FontSet) in `carto.js`. These are useful for supporting multiple character sets and fallback fonts for distributed styles. | ||
By defining multiple fonts in a `text-face-name` definition, you create [FontSets](http://trac.mapnik.org/wiki/FontSet) in `CartoCSS`. These are useful for supporting multiple character sets and fallback fonts for distributed styles. | ||
@@ -272,3 +271,3 @@ <table> | ||
Currently `carto.js` is designed to be invoked from [node.js](http://nodejs.org/). | ||
Currently CartoCSS is designed to be invoked from [node.js](http://nodejs.org/). | ||
The `Renderer` interface is the main API for developers, and it takes an MML file as a string as input. | ||
@@ -303,3 +302,3 @@ | ||
`carto.js` is based on [less.js](https://github.com/cloudhead/less.js), a CSS compiler written by Alexis Sellier. | ||
CartoCSS is based on [less.js](https://github.com/cloudhead/less.js), a CSS compiler written by Alexis Sellier. | ||
@@ -306,0 +305,0 @@ It depends on: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
181881
50
3196
308
1