Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but 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
Max Howell Improve escapes with a `bs.js` library
I resisted this, but it makes BS more useful, so what can you do?
136788d
Max Howell Update README; create TODO 18ab374
Max Howell 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
4 BullScript.JSON-tmLanguage
View
@@ -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" }
201 README.md
View
@@ -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.
69 TODO.md
View
@@ -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);
+}}
+```
26 bs.js
View
@@ -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 || '';
+ }
+ };
+})();
40 bsc
View
@@ -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
21 tests
View
@@ -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.