diff --git a/packages/blaze-tools/package.js b/packages/blaze-tools/package.js index d65238831..b5dbb0633 100644 --- a/packages/blaze-tools/package.js +++ b/packages/blaze-tools/package.js @@ -6,22 +6,15 @@ Package.describe({ }); Package.onUse(function (api) { - api.use('underscore@1.0.9'); - - api.export('BlazeTools'); - + api.use('ecmascript'); api.use('htmljs@1.1.0-beta.2'); - api.addFiles([ - 'preamble.js', - 'tokens.js', - 'tojs.js' - ]); + api.mainModule('preamble.js'); }); Package.onTest(function (api) { api.use('tinytest@1.0.11'); - api.use('underscore@1.0.9'); + api.use('ecmascript'); api.use('blaze-tools'); api.use('html-tools@1.1.0-beta.2'); diff --git a/packages/blaze-tools/preamble.js b/packages/blaze-tools/preamble.js index 2211e646a..0ea86ee21 100644 --- a/packages/blaze-tools/preamble.js +++ b/packages/blaze-tools/preamble.js @@ -1 +1,27 @@ -BlazeTools = {}; + +import { + EmitCode, + toJSLiteral, + toObjectLiteralKey, + ToJSVisitor, + toJS +} from './tojs'; + +import { + parseNumber, + parseIdentifierName, + parseExtendedIdentifierName, + parseStringLiteral +} from './tokens'; + +export const BlazeTools = { + EmitCode, + toJSLiteral, + toObjectLiteralKey, + ToJSVisitor, + toJS, + parseNumber, + parseIdentifierName, + parseExtendedIdentifierName, + parseStringLiteral +}; diff --git a/packages/blaze-tools/tojs.js b/packages/blaze-tools/tojs.js index 730dc24d5..d50bce98c 100644 --- a/packages/blaze-tools/tojs.js +++ b/packages/blaze-tools/tojs.js @@ -1,50 +1,51 @@ +import { HTML } from 'meteor/htmljs'; -BlazeTools.EmitCode = function (value) { - if (! (this instanceof BlazeTools.EmitCode)) + +export function EmitCode (value) { + if (! (this instanceof EmitCode)) // called without `new` - return new BlazeTools.EmitCode(value); + return new EmitCode(value); if (typeof value !== 'string') - throw new Error('BlazeTools.EmitCode must be constructed with a string'); + throw new Error('EmitCode must be constructed with a string'); this.value = value; -}; -BlazeTools.EmitCode.prototype.toJS = function (visitor) { +} + +EmitCode.prototype.toJS = function (visitor) { return this.value; }; // Turns any JSONable value into a JavaScript literal. -toJSLiteral = function (obj) { +export function toJSLiteral (obj) { // See for `\u2028\u2029`. // Also escape Unicode surrogates. return (JSON.stringify(obj) .replace(/[\u2028\u2029\ud800-\udfff]/g, function (c) { return '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4); })); -}; -BlazeTools.toJSLiteral = toJSLiteral; +} var jsReservedWordSet = (function (set) { - _.each("abstract else instanceof super boolean enum int switch break export interface synchronized byte extends let this case false long throw catch final native throws char finally new transient class float null true const for package try continue function private typeof debugger goto protected var default if public void delete implements return volatile do import short while double in static with".split(' '), function (w) { + "abstract else instanceof super boolean enum int switch break export interface synchronized byte extends let this case false long throw catch final native throws char finally new transient class float null true const for package try continue function private typeof debugger goto protected var default if public void delete implements return volatile do import short while double in static with".split(' ').forEach(function (w) { set[w] = 1; }); return set; })({}); -toObjectLiteralKey = function (k) { +export function toObjectLiteralKey (k) { if (/^[a-zA-Z$_][a-zA-Z$0-9_]*$/.test(k) && jsReservedWordSet[k] !== 1) return k; return toJSLiteral(k); -}; -BlazeTools.toObjectLiteralKey = toObjectLiteralKey; +} var hasToJS = function (x) { return x.toJS && (typeof (x.toJS) === 'function'); }; -ToJSVisitor = HTML.Visitor.extend(); +export const ToJSVisitor = HTML.Visitor.extend(); ToJSVisitor.def({ visitNull: function (nullOrUndefined) { return 'null'; @@ -149,8 +150,7 @@ ToJSVisitor.def({ return null; } }); -BlazeTools.ToJSVisitor = ToJSVisitor; -BlazeTools.toJS = function (content) { +export function toJS (content) { return (new ToJSVisitor).visit(content); -}; +} diff --git a/packages/blaze-tools/token_tests.js b/packages/blaze-tools/token_tests.js index 91aa8bd36..530be1dd3 100644 --- a/packages/blaze-tools/token_tests.js +++ b/packages/blaze-tools/token_tests.js @@ -1,3 +1,6 @@ +import { BlazeTools } from 'meteor/blaze-tools'; +import { HTMLTools } from 'meteor/html-tools'; + Tinytest.add("blaze-tools - token parsers", function (test) { var run = function (func, input, expected) { @@ -40,7 +43,7 @@ Tinytest.add("blaze-tools - token parsers", function (test) { runValue(parseNumber, "-0xa", -10); runValue(parseNumber, "1e+1", 10); - _.each([parseIdentifierName, parseExtendedIdentifierName], function (f) { + [parseIdentifierName, parseExtendedIdentifierName].forEach(function (f) { run(f, "a", "a"); run(f, "true", "true"); run(f, "null", "null"); diff --git a/packages/blaze-tools/tokens.js b/packages/blaze-tools/tokens.js index 441d070fb..3f13d6793 100644 --- a/packages/blaze-tools/tokens.js +++ b/packages/blaze-tools/tokens.js @@ -52,7 +52,7 @@ var rLineContinuation = /^\\(\r\n|[\u000A\u000D\u2028\u2029])/; -BlazeTools.parseNumber = function (scanner) { +export function parseNumber (scanner) { var startPos = scanner.pos; var isNegative = false; @@ -75,9 +75,9 @@ BlazeTools.parseNumber = function (scanner) { var value = Number(matchText); value = (isNegative ? -value : value); return { text: text, value: value }; -}; +} -BlazeTools.parseIdentifierName = function (scanner) { +export function parseIdentifierName (scanner) { var startPos = scanner.pos; var rest = scanner.rest(); var match = rIdentifierPrefix.exec(rest); @@ -106,13 +106,13 @@ BlazeTools.parseIdentifierName = function (scanner) { } return scanner.input.substring(startPos, scanner.pos); -}; +} -BlazeTools.parseExtendedIdentifierName = function (scanner) { +export function parseExtendedIdentifierName (scanner) { // parse an identifier name optionally preceded by '@' if (scanner.peek() === '@') { scanner.pos++; - var afterAt = BlazeTools.parseIdentifierName(scanner); + var afterAt = parseIdentifierName(scanner); if (afterAt) { return '@' + afterAt; } else { @@ -120,11 +120,11 @@ BlazeTools.parseExtendedIdentifierName = function (scanner) { return null; } } else { - return BlazeTools.parseIdentifierName(scanner); + return parseIdentifierName(scanner); } -}; +} -BlazeTools.parseStringLiteral = function (scanner) { +export function parseStringLiteral (scanner) { var startPos = scanner.pos; var rest = scanner.rest(); var match = rStringQuote.exec(rest); @@ -190,4 +190,4 @@ BlazeTools.parseStringLiteral = function (scanner) { var text = scanner.input.substring(startPos, scanner.pos); var value = JSON.parse(jsonLiteral); return { text: text, value: value }; -}; +} diff --git a/packages/html-tools/charref.js b/packages/html-tools/charref.js index ff437ee8b..c0725abb0 100644 --- a/packages/html-tools/charref.js +++ b/packages/html-tools/charref.js @@ -1,3 +1,4 @@ +import { makeRegexMatcher } from './scanner'; // http://www.whatwg.org/specs/web-apps/current-work/multipage/entities.json @@ -2360,7 +2361,7 @@ var isLegalCodepoint = function (cp) { // either `"`, `'`, or `>` and is supplied when parsing attribute values. NOTE: In the current spec, the // value of `allowedChar` doesn't actually seem to end up mattering, but there is still some debate about // the right approach to ampersands. -getCharacterReference = HTMLTools.Parse.getCharacterReference = function (scanner, inAttribute, allowedChar) { +export function getCharacterReference (scanner, inAttribute, allowedChar) { if (scanner.peek() !== '&') // no ampersand return null; @@ -2411,4 +2412,4 @@ getCharacterReference = HTMLTools.Parse.getCharacterReference = function (scanne return null; } } -}; +} diff --git a/packages/html-tools/charref_tests.js b/packages/html-tools/charref_tests.js index 35a991aeb..2c7d555ad 100644 --- a/packages/html-tools/charref_tests.js +++ b/packages/html-tools/charref_tests.js @@ -1,3 +1,5 @@ +import { HTMLTools } from 'meteor/html-tools'; + var Scanner = HTMLTools.Scanner; var getCharacterReference = HTMLTools.Parse.getCharacterReference; @@ -19,7 +21,7 @@ Tinytest.add("html-tools - entities", function (test) { test.equal(result, { t: 'CharRef', v: match, - cp: _.map(codepoints, + cp: codepoints.map( function (x) { return (typeof x === 'string' ? x.charCodeAt(0) : x); }) }); diff --git a/packages/html-tools/main.js b/packages/html-tools/main.js new file mode 100644 index 000000000..1221313c2 --- /dev/null +++ b/packages/html-tools/main.js @@ -0,0 +1,27 @@ + +import { getCharacterReference } from './charref'; +import { asciiLowerCase, properCaseTagName, properCaseAttributeName} from "./utils"; +import { TemplateTag } from './templatetag' +import { Scanner } from './scanner'; +import { parseFragment, codePointToString, getContent, getRCData } from './parse'; +import { getComment, getDoctype, getHTMLToken, getTagToken, TEMPLATE_TAG_POSITION } from './tokenize'; + +export const HTMLTools = { + asciiLowerCase, + properCaseTagName, + properCaseAttributeName, + TemplateTag, + Scanner, + parseFragment, + codePointToString, + TEMPLATE_TAG_POSITION, + Parse: { + getCharacterReference, + getContent, + getRCData, + getComment, + getDoctype, + getHTMLToken, + getTagToken, + } +}; diff --git a/packages/html-tools/package.js b/packages/html-tools/package.js index 0379388eb..82541aba0 100644 --- a/packages/html-tools/package.js +++ b/packages/html-tools/package.js @@ -6,24 +6,16 @@ Package.describe({ }); Package.onUse(function (api) { - api.export('HTMLTools'); - + api.use('ecmascript@0.14.4'); api.use('htmljs@1.1.0-beta.2'); api.imply('htmljs@1.1.0-beta.2'); - api.addFiles([ - 'utils.js', - 'scanner.js', - 'charref.js', - 'tokenize.js', - 'templatetag.js', - 'parse.js' - ]); + api.mainModule('main.js'); }); Package.onTest(function (api) { + api.use('ecmascript'); api.use('tinytest@1.0.11'); - api.use('underscore@1.0.9'); api.use('html-tools'); api.use('htmljs@1.1.0-beta.2'); diff --git a/packages/html-tools/parse.js b/packages/html-tools/parse.js index 7b3296327..248b1ab3c 100644 --- a/packages/html-tools/parse.js +++ b/packages/html-tools/parse.js @@ -1,7 +1,11 @@ +import { HTML } from 'meteor/htmljs'; +import { Scanner } from './scanner'; +import { properCaseAttributeName } from './utils'; +import { getHTMLToken, isLookingAtEndTag } from './tokenize'; // Parse a "fragment" of HTML, up to the end of the input or a particular // template tag (using the "shouldStop" option). -HTMLTools.parseFragment = function (input, options) { +export function parseFragment(input, options) { var scanner; if (typeof input === 'string') scanner = new Scanner(input); @@ -69,14 +73,14 @@ HTMLTools.parseFragment = function (input, options) { } return result; -}; +} // Take a numeric Unicode code point, which may be larger than 16 bits, // and encode it as a JavaScript UTF-16 string. // // Adapted from // http://stackoverflow.com/questions/7126384/expressing-utf-16-unicode-characters-in-javascript/7126661. -codePointToString = HTMLTools.codePointToString = function(cp) { +export function codePointToString(cp) { if (cp >= 0 && cp <= 0xD7FF || cp >= 0xE000 && cp <= 0xFFFF) { return String.fromCharCode(cp); } else if (cp >= 0x10000 && cp <= 0x10FFFF) { @@ -97,9 +101,9 @@ codePointToString = HTMLTools.codePointToString = function(cp) { } else { return ''; } -}; +} -getContent = HTMLTools.Parse.getContent = function (scanner, shouldStopFunc) { +export function getContent (scanner, shouldStopFunc) { var items = []; while (! scanner.isEOF()) { @@ -204,7 +208,7 @@ getContent = HTMLTools.Parse.getContent = function (scanner, shouldStopFunc) { return items[0]; else return items; -}; +} var pushOrAppendString = function (items, string) { if (items.length && @@ -215,7 +219,7 @@ var pushOrAppendString = function (items, string) { }; // get RCDATA to go in the lowercase (or camel case) tagName (e.g. "textarea") -getRCData = HTMLTools.Parse.getRCData = function (scanner, tagName, shouldStopFunc) { +export function getRCData(scanner, tagName, shouldStopFunc) { var items = []; while (! scanner.isEOF()) { @@ -250,7 +254,7 @@ getRCData = HTMLTools.Parse.getRCData = function (scanner, tagName, shouldStopFu return items[0]; else return items; -}; +} var getRawText = function (scanner, tagName, shouldStopFunc) { var items = []; @@ -350,7 +354,7 @@ var parseAttrs = function (attrs) { var outValue = (inValue.length === 0 ? '' : (outParts.length === 1 ? outParts[0] : outParts)); - var properKey = HTMLTools.properCaseAttributeName(k); + var properKey = properCaseAttributeName(k); result[properKey] = outValue; } diff --git a/packages/html-tools/parse_tests.js b/packages/html-tools/parse_tests.js index 3bc69be8c..5029b6714 100644 --- a/packages/html-tools/parse_tests.js +++ b/packages/html-tools/parse_tests.js @@ -1,3 +1,7 @@ +import { HTML } from 'meteor/htmljs'; +import { HTMLTools } from 'meteor/html-tools'; +import { BlazeTools} from 'meteor/blaze-tools'; + var Scanner = HTMLTools.Scanner; var getContent = HTMLTools.Parse.getContent; @@ -190,8 +194,8 @@ Tinytest.add("html-tools - parseFragment", function (test) { test.equal(BlazeTools.toJS(HTMLTools.parseFragment("

Hello

")), BlazeTools.toJS(DIV(P({id:'foo'}, 'Hello')))); - _.each(['asdf
', '{{!foo}}
', '{{!foo}}
', - 'asdf', '{{!foo}}', '{{!foo}} '], function (badFrag) { + ['asdf
', '{{!foo}}
', '{{!foo}}
', + 'asdf', '{{!foo}}', '{{!foo}} '].forEach(function (badFrag) { test.throws(function() { HTMLTools.parseFragment(badFrag); }, /Unexpected HTML close tag/); diff --git a/packages/html-tools/scanner.js b/packages/html-tools/scanner.js index d110a8a81..6f1b51726 100644 --- a/packages/html-tools/scanner.js +++ b/packages/html-tools/scanner.js @@ -9,10 +9,10 @@ // * `scanner.isEOF()` - true if `pos` is at or beyond the end of `input` // * `scanner.fatal(msg)` - throw an error indicating a problem at `pos` -Scanner = HTMLTools.Scanner = function (input) { +export function Scanner (input) { this.input = input; // public, read-only this.pos = 0; // public, read-write -}; +} Scanner.prototype.rest = function () { // Slicing a string is O(1) in modern JavaScript VMs (including old IE). @@ -69,7 +69,7 @@ Scanner.prototype.peek = function () { // the current position of the scanner is advanced. If it fails, the // current position is not advanced and a falsy value (typically null) // is returned. -makeRegexMatcher = function (regex) { +export function makeRegexMatcher(regex) { return function (scanner) { var match = regex.exec(scanner.rest()); @@ -79,4 +79,4 @@ makeRegexMatcher = function (regex) { scanner.pos += match[0].length; return match[1] || match[0]; }; -}; +} diff --git a/packages/html-tools/templatetag.js b/packages/html-tools/templatetag.js index f94f9fd21..3bc952db7 100644 --- a/packages/html-tools/templatetag.js +++ b/packages/html-tools/templatetag.js @@ -11,17 +11,17 @@ var _assign = function (tgt, src) { }; -HTMLTools.TemplateTag = function (props) { - if (! (this instanceof HTMLTools.TemplateTag)) +export function TemplateTag (props) { + if (! (this instanceof TemplateTag)) // called without `new` - return new HTMLTools.TemplateTag; + return new TemplateTag; if (props) _assign(this, props); -}; +} -_assign(HTMLTools.TemplateTag.prototype, { - constructorName: 'HTMLTools.TemplateTag', +_assign(TemplateTag.prototype, { + constructorName: 'TemplateTag', toJS: function (visitor) { return visitor.generateCall(this.constructorName, _assign({}, this)); diff --git a/packages/html-tools/tokenize.js b/packages/html-tools/tokenize.js index de0b9c066..55cbd3ecf 100644 --- a/packages/html-tools/tokenize.js +++ b/packages/html-tools/tokenize.js @@ -1,3 +1,8 @@ +import { asciiLowerCase, properCaseTagName, properCaseAttributeName } from './utils'; +import { TemplateTag } from './templatetag'; +import { getCharacterReference } from './charref'; +import { makeRegexMatcher } from './scanner'; + // Token types: // // { t: 'Doctype', @@ -54,7 +59,7 @@ var convertCRLF = function (str) { return str.replace(/\r\n?/g, '\n'); }; -getComment = HTMLTools.Parse.getComment = function (scanner) { +export function getComment (scanner) { if (scanner.rest().slice(0, 4) !== '