Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: mxcl/bs
base: c3871fee24
...
head fork: mxcl/bs
compare: 5066fe3115
  • 3 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Mar 16, 2013
@mxcl Improve escapes with a `bs.js` library
I resisted this, but it makes BS more useful, so what can you do?
136788d
@mxcl Update README; create TODO 18ab374
@mxcl DRY String.bsubst 5066fe3
Showing with 190 additions and 171 deletions.
  1. +2 −2 BullScript.JSON-tmLanguage
  2. +67 −134 README.md
  3. +69 −0 TODO.md
  4. +26 −0 bs.js
  5. +15 −25 bsc
  6. +11 −10 tests
View
4 BullScript.JSON-tmLanguage
@@ -8,7 +8,7 @@
"0": { "name": "string.quoted.double.js" }
},
"patterns": [
- { "begin": "#[nxX]?{",
+ { "begin": "#[nNxX]?{",
"end": "}",
"patterns": [
{ "include": "$self" }
@@ -28,7 +28,7 @@
"1": { "name": "entity.name.tag.html" }
},
"patterns": [
- { "begin": "#[nxX]?{",
+ { "begin": "#[nNxX]?{",
"end": "}",
"patterns": [
{ "include": "$self" }
View
201 README.md
@@ -13,53 +13,44 @@ something else that is “better”.
Alpha Quality
=============
-The test-suite has holes, and some features are not implemented, but we’re
-using it for our projects, so you may like to also.
-
-Bugs
-====
-The Bullscript compiler is a messy bunch of code, but it’s short and only one
-file. You can probably figure out how to improve/fix it. But failing that just
-open a ticket.
+The test-suite no doubt has holes. So you may have to fix some bugs if you use
+it at this stage. But, we’re actively developing BS, so hgopefully its quality
+will rapidly improve.
Examples
========
+Inline HTML
+-----------
```js
-/*bs*/ var foo = "Hello #{name}, ‘sup?";
-/*js*/ var foo = "Hello " + name + ", ‘sup?";
-```
+/** bs **/
-Easy enough, Ruby-style variable substitution. CoffeeScript does that too,
-init? But how about writing HTML inline!
+var bar = <div class="abc">
+ Hello <a href='#{href}'>#{name}</a>, sup?
+ </div>;
-```js
-/*bs*/ var bar = <div class="abc">
- Hello <a href='#{href}'>#{name}</a>, sup?
- </div>;
+/** js **/
-/*js*/ var bar = '<div class="abc">'+
- 'Hello <a href="' + href + '">' + name + '</a>, sup?'+
- '</div>';
+var bar = $('<div class="abc"> '+
+ 'Hello <a href="' + href + '">' + name + '</a>, sup? '+
+ '</div>');
```
-Multi-line too! Notice how BS is generated with a one-to-one line mapping?
-
-Being able to write HTML inline makes templates not-always-required. But
-that’s up to you.
-
-How about automatic jQuerization?
+It’s time to stop writing your HTML5 applications across multiple files.
+Variable Substitution
+---------------------
```js
-/*bs*/ var $bar = <ol><li>foo</ol>;
-/*js*/ var $bar = $('<ol><li>foo</ol>');
+/** bs **/ var foo = "Hello #{name}, ‘sup?";
+/** js **/ var foo = "Hello " + name + ", ‘sup?";
```
-Multiline strings:
+Multiline Strings
+-----------------
```js
"""Line one
- Line two
+ Line #{two}
Line three"""
```
@@ -67,127 +58,69 @@ Becomes:
```js
"Line one\n"+
- "Line two\n"+
+ "Line " + two + "\n"+
"Line three"
```
-Because we're generating HTML, we don't add the leading whitespace to the
-string on the extra lines. We do however add a trailing newline character.
-
-Fancy escaping:
-
+Fancy Escaping
+--------------
```js
-/*bs*/ "foo #n{bar} jee"
-/*js*/ "foo " + (bar || '') + " jee"
+/** bs **/ "foo #n{bar} jee"
+/** js* */ "foo " + (bar || '') + " jee"
```
```js
-/*bs*/ "http://foo.com/#x{bar}/jee"
-/*js*/ "http://foo.com/" + encodeURIComponent(bar) + "/jee"
+/** bs **/ "http://foo.com/#x{bar}/jee"
+/** js **/ "http://foo.com/" + encodeURIComponent(bar) + "/jee"
```
-TODO - <<
-=========
-How about a new operator that is handy for jQuery?
-
-```js
-/*bs*/ $bar << <li>foo << <li>bar;
-/*js*/ $bar.append('<li>foo').append('<li>bar');
+In fact there is more to this: they call through to bs.js so that the escapes
+are more useful. `#n{}` will output an empty string for `null` and
+`undefined`, while `#N{}` will do so for empty Arrays, Objects and anything
+that is `falsy`. `#x{}` does “pretty” escaping, ie. `encodeURIComponent` but
+replacing `%20`s with `+`s, while `#N{}` does *full* escaping, that is
+`encodeURIComponent` but it also encodes `!'()` which doesn’t hurt, but can
+avoid certain categories of bug. If you want vanilla `encodeURIComponent` then
+(currently) you’ll have to call it yourself.
+
+Using BullScript
+================
+Currently we only have the compiler: `bsc`.
+
+Using it in eg. Sinatra is thus (you will need to adapt paths):
+
+```rb
+get '/*.js' do |fn|
+ `./bsc #{fn}.js`
+end
```
-Note, this operator is a little unfortunate considering the angular brackets
-of the inline HTML, so we should think of something better.
-
-Use parenthesis to append at different levels in the DOM:
+And when deploying just adapt your build-system to compile `bs` to `js`, eg.
+for `make` here’s an implicit rule you can use:
-```js
-$bar << (<ol> << <li>#{foo} << <li>#{bar});
+```Makefile
+%.js: %.bs
+ ./bsc $< > $@
```
-HTML Blocks Caveats
+Inline HTML Caveats
===================
-Since many of the things you write inside HTML blocks are in fact valid
-Javascript, and multiline strings are not typically valid in Javascript,
-there are some caveats regarding these special blocks.
-
-Namely we will continue to suck everything after a <\w into an HTML block
-until you terminate it with a trailing semi-colon or a << operator.
-
-Probably ideally we would use proper JS statement termination rules, and
-detect when a newline is in fact a terminator. We could do this by analysing
-your markup and seeing that you have closed the opening block.
-
-We have not done that yet though. Please fork and fix! Or suggest better
-solutions in a ticket! :)
-
-
-HTML Blocks & Whitespace
-========================
-We add a space at the ends of HTML lines:
-
- <b>Boo
- Foo
- Goo</b>
-
-Will compile to:
-
- '<b>Boo '+
- 'Foo '+
- Goo'</b>'
+You have to cleanly terminate your HTML tags. This is how the parser
+determines where HTML ends. So if you start with a <div> end with a </div>.
+Though having said this, we understand tags like <img> too. Also you can do
+this:
-We do this because if you wrote that HTML the newline would count as
-whitespace. We use a space instead of a newline as it’s less visual-noise.
-
-
-Caveats
-=======
-HTML blocks need to be terminated by a semi-colon and then straight after a
-newline. This way semi-colons in the HTML are ignored. Flakey, we know.
-
-Currently we can't figure out the HTML portion unless you choose not to use
-the less-than operator (<) without whitespace like so:
-
- if (1 <abc)
-
-Currently you can't put string substituions inside of string substitutions,
-like:
-
- "foo #{bar("#{bar}")} bar"
-
-
-MAYBE
-=====
-* Make the value of this in our-style maps be the array it is invoked on by
-default, eg:
-
- array.map(function(obj, array) { /* this is array now due to 2nd param */} );
-
-* Print and return, return operator (only if some global logging is set, debug only):
-
- printurn array.map(foo); // => var a = array.map(foo); console.log(a); return a;
-
-* Inline SASS so you can define variables and use them in your JS *and* your CSS!
-* Defaults for function parameters:
-
- function foo(a, b = []) {
- a = b;
- }
- function foo(a, b) { b = b || [];
- a = b;
- }
-
-* Convenience try block syntax:
-
- function foo() try {
- } catch (e) {
- }
- function foo() { try {
- } catch (e) {
- }}
+```js
+var a = <div>foo</div>
+ <b>blah</b>
+var b = 2;
+```
-* How about Ruby-style block syntax:
+Additionally, (currently) the parser will be confused by JavaScript of this
+kind:
```js
-/* bs */ [1,2,3].map{ |x| x * 2 }.each{ |x| console.log(x); }
-/* js */ [1,2,3].map(function(x){ return x * 2; }).each(function(x){ console.log(x); })
+if (a <bc) { bar(); }
```
+
+Heck, the above even breaks Sublime Text’s Markdown syntax highlighting.
View
69 TODO.md
@@ -0,0 +1,69 @@
+Maybe This Stuff?
+=================
+`<<`
+----
+```js
+/** bs **/ $bar << <li>foo << <li>bar;
+/** js **/ $bar.append('<li>foo').append('<li>bar');
+```
+
+This is cool because: it makes it easier and more readable to construct your
+HTML programmatically, otherwise you get lots of nested brackets.
+
+Note, this operator is a little unfortunate considering the angular brackets
+of the inline HTML, so we should think of something better.
+
+Use parenthesis to append at different levels in the DOM:
+
+```js
+$bar << (<ol> << <li>#{foo} << <li>#{bar});
+```
+
+Ruby-style Block Syntax
+-----------------------
+```js
+/** bs **/ [1,2,3].map{ |x| x * 2 }.each{ |x| console.log(x); }
+/** js **/ [1,2,3].map(function(x){ return x * 2; }).each(function(x){ console.log(x); })
+```
+
+* Rationale: less visual noise
+* Make the “context” of the map call be the iterated element
+
+`p` Debug Logger
+----------------
+```js
+return&log foo;
+```
+
+* returns the value, but logs it first.
+
+Inline SCSS
+-----------
+We have *Inline HTML*, so we should also support inline CSS, but let’s do it
+with SCSS and then (with a bit of effort), support having variables in both
+the JS and the CSS.
+
+Function Parameter Defaults
+---------------------------
+This is common to compile-to-JavaScript languages. But I’m not sure about it
+as—frankly—it doesn’t feel very “Javascripty”.
+
+Convenience `try` syntax for functions
+--------------------------------------
+```js
+function foo() try {
+ bar();
+} catch (e) {
+ console.error(e);
+}
+```
+
+Becomes:
+
+```js
+function foo() { try {
+ bar();
+} catch (e) {
+ console.error(e);
+}}
+```
View
26 bs.js
@@ -0,0 +1,26 @@
+(function() {
+ bs = {
+ x: function(y) {
+ if (y === null || y === undefined)
+ return '';
+ return encodeURIComponent(y).replace('%20', '+');
+ },
+ X: function(y) {
+ if (y === null || y === undefined)
+ return '';
+ return encodeURIComponent(y).replace(/[!'()]/g, escape).replace(/\\*/g, '%2A');
+ },
+ n: function(y) {
+ if (y === null || y === undefined)
+ return '';
+ return y;
+ },
+ N: function(y) {
+ if (y instanceof Array && y.length <= 0)
+ return '';
+ if (y instanceof Object && Object.keys(y).length <= 0)
+ return '';
+ return y || '';
+ }
+ };
+})();
View
40 bsc
@@ -140,20 +140,19 @@ def tokenize
end
class String
- def bsubst sep = '"'
- self.gsub(/#([nxX]?)\{(.*?)\}/) do
- inner = case $1
- when 'n'
- "((#{$2}) || '')"
- when 'X'
- "encodeURIComponent(#{$2}).replace(/[!'()]/g, escape).replace(/\\*/g, '%2A')"
- when 'x'
- "encodeURIComponent(#{$2}).replace('%20', '+')"
+ def bsubst sep = "'"
+ split(/(#[nNxX]?\{.*?\})/).map do |part|
+ if part =~ /#([nNxX]?)\{(.*?)\}/
+ subst = if $1 and $1.length > 0
+ "bs.#$1(#$2)"
+ else
+ "(#$2)"
+ end
+ %Q{#{sep} + #{subst} + #{sep}}
else
- "(#{$2})"
+ part.gsub(sep, %{\\\\#{sep}})
end
- %Q{#{sep} + #{inner} + #{sep}}
- end
+ end.join
end
end
@@ -161,24 +160,15 @@ end
tokenize do |type, string, opts|
case type
when :string
- print string.bsubst
+ print %{"#{string[1..-2].bsubst('"')}"}
when :multi
string = string[3..-4] # remove surrounding triple quotes
- string = string.gsub("'", "\\\\'")
- string = string.bsubst("'")
+ string = string.bsubst
string = string.gsub(/\s*\n(\s*)/m, %Q{\\n'+\n\\1'})
print %Q{'#{string}'}
when :html
- string = string.split(/(#[nx]?\{.*?\})/).map do |part|
- if part.start_with? '#'
- part.bsubst("'")
- else
- part.gsub(%{'}, %{\\\\'}) # escape quotes
- end
- end.join
+ string = string.bsubst
string.gsub!(/\s*\n(\s*)/m, %Q{ '+\n\\1'})
- string = "'#{string}'"
- string = "$(#{string})"
- print string
+ print "$('#{string}')"
end
end
View
21 tests
@@ -62,11 +62,11 @@ class BullTests < Test::Unit::TestCase
end
def test_falsy_subst
- assert_equal %q{"foo #n{bar} foo"}.to_js, %q{"foo " + ((bar) || '') + " foo"}
+ assert_equal %q{"foo #n{bar} foo"}.to_js, %q{"foo " + bs.n(bar) + " foo"}
end
def test_URI_encoded_subst
- assert_equal %q{"foo #x{bar} foo"}.to_js, %q{"foo " + encodeURIComponent(bar).replace('%20', '+') + " foo"}
+ assert_equal %q{"foo #x{bar} foo"}.to_js, %q{"foo " + bs.x(bar) + " foo"}
end
def test_html1
@@ -197,15 +197,16 @@ class BullTests < Test::Unit::TestCase
def test_multiline_with_internal_quotes
input = <<-end.to_js
- """foo
- bar \#{jee || ''} haha
- mooface
- """
+ """foo
+ bar \#{jee || ''} haha
+ mooface
+ """
+ end
output = <<-end.to_js
- 'foo\n'+
- 'bar ' + (jee || '') + ' haha\n'+
- 'mooface\n'+
- ''
+ 'foo\\n'+
+ 'bar ' + (jee || '') + ' haha\\n'+
+ 'mooface\\n'+
+ ''
end
assert_equal output, input
end

No commit comments for this range

Something went wrong with that request. Please try again.