diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 0000000..6866ac2
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "vendor"
+}
diff --git a/.gitignore b/.gitignore
index fc428e3..4fc7c8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@ Thumbs.db
.grunt
node_modules
bower_components
+
+heroku
+heroku.pub
diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..489b270
--- /dev/null
+++ b/Procfile
@@ -0,0 +1 @@
+web: node server.js
diff --git a/app/bootstrap.jsx b/app/bootstrap.jsx
new file mode 100644
index 0000000..81a4e7b
--- /dev/null
+++ b/app/bootstrap.jsx
@@ -0,0 +1,20 @@
+/** @jsx React.DOM */
+(function() {
+ var feature;
+
+ var requiredFeatures = {
+ "the selectors API": document.querySelector,
+ "ES5 array methods": Array.prototype.forEach,
+ "DOM level 2 events": window.addEventListener,
+ "the HTML5 history API": window.history.pushState
+ };
+
+ for (feature in requiredFeatures) {
+ if (!requiredFeatures[feature]) {
+ return alert("Sorry, but your browser does not support " + feature + " so this app won't work properly.");
+ }
+ }
+
+ window.app = React.renderComponent(, document.body);
+
+})();
diff --git a/app/component/network.jsx b/app/component/network.jsx
new file mode 100644
index 0000000..be88698
--- /dev/null
+++ b/app/component/network.jsx
@@ -0,0 +1,88 @@
+/** @jsx React.DOM */
+var Network = React.createClass({
+
+ getInitialState: function() {
+ return {
+ collapsible: window.innerWidth <= 800,
+ open: false
+ };
+ },
+
+ handleToggle: function() {
+ this.setState({ open: !this.state.open });
+ },
+
+ handleResize: function() {
+ this.setState({ collapsible: window.innerWidth <= 800 });
+ },
+
+ componentWillMount: function() {
+ // Simple event debouncing to avoid multiple recalculations
+ this.debounce = utils.debounceEvent(this.handleResize, 250);
+ window.addEventListener("resize", this.debounce, false);
+ },
+
+ componentWillUnmount: function() {
+ window.removeEventListener("resize", this.debounce, false);
+ },
+
+ render: function() {
+ var networkData = this.props.networkData;
+ var networkLineCodes = Object.keys(networkData.lines);
+
+ var toggleText = this.state.open ? "Close" : "Open";
+ var toggleClass = this.state.collapsible ? (this.state.open ? "is-open" : "is-closed") : "is-static";
+
+ var generatedForms = networkLineCodes.map(function(lineCode, i) {
+ return ;
+ }, this);
+
+ return (
+
+ {generatedForms}
+
+
+ );
+ }
+
+});
+
+var Line = React.createClass({
+
+ handleSubmit: function(event) {
+ event.preventDefault();
+
+ // Dispatch an event for other components to capture
+ var updateEvent = new CustomEvent("tt:update", {
+ detail: {
+ station: this.refs.station.getDOMNode().value,
+ line: this.props.lineCode
+ },
+ bubbles: true
+ });
+
+ this.refs.form.getDOMNode().dispatchEvent(updateEvent);
+ },
+
+ render: function() {
+ var lineCode = this.props.lineCode;
+ var networkData = this.props.networkData;
+ var stationsOnThisLine = networkData.stationsOnLines[lineCode];
+
+ var generatedOptions = stationsOnThisLine.map(function(stationCode, i) {
+ return ;
+ });
+
+ return (
+
+ );
+ }
+
+});
diff --git a/app/component/predictions.jsx b/app/component/predictions.jsx
new file mode 100644
index 0000000..c5b3e8b
--- /dev/null
+++ b/app/component/predictions.jsx
@@ -0,0 +1,173 @@
+/** @jsx React.DOM */
+var Predictions = React.createClass({
+
+ getInitialState: function() {
+ return { status: this.props.line && this.props.station ? "loading" : "welcome" };
+ },
+
+ fetchPredictions: function(line, station) {
+ // The circle line isn't defined in the API but shares platforms with other lines
+ if (line === "O") {
+ line = utils.mapCircleLineStation(station, this.props.networkData);
+ }
+
+ var api = "http://cloud.tfl.gov.uk/TrackerNet/PredictionDetailed/" + line + "/" + station;
+
+ this.setState({ status: "loading" });
+
+ // The TrackerNet API does not support cross-origin requests so we must use a proxy
+ utils.httpRequest(utils.proxyRequestURL(api), this.predictionsSuccess, this.predictionsError);
+ },
+
+ predictionsError: function(error) {
+ this.setState({
+ status: "error",
+ predictionData: null
+ });
+
+ // Pipe the error into your error logging setup
+ // Airbrake.push({ error: error });
+ },
+
+ predictionsSuccess: function(responseDoc) {
+ // Because we're using a proxy it will return a 200 and XML even if the
+ // TrackerNet API is unavailble or request was invalid.
+ if (!utils.validateResponse(responseDoc)) {
+ return this.predictionError(new Error("Invalid API response"));
+ }
+
+ this.setState({
+ status: "success",
+
+ // Dealing with XML in the browser is so ugly that I've
+ // used 'models' to abstract it away.
+ predictionData: new Prediction(responseDoc)
+ });
+ },
+
+ resetPoll: function(line, station) {
+ this.fetchPredictions(line, station);
+
+ if (this.poll) {
+ clearInterval(this.poll);
+ }
+
+ this.poll = setInterval(this.fetchPredictions.bind(this, line, station), 1000 * 30);
+ },
+
+ componentDidMount: function() {
+ if (this.props.line && this.props.station) {
+ this.resetPoll(this.props.line, this.props.station);
+ }
+ },
+
+ componentWillUnmount: function() {
+ clearInterval(this.poll);
+ },
+
+ componentWillReceiveProps: function(newProps) {
+ this.resetPoll(newProps.line, newProps.station);
+ },
+
+ shouldComponentUpdate: function(newProps, newState) {
+ // Only update when line/station changes or new predictions load otherwise the
+ // loading notice will be displayed when refreshing current predictions.
+ return this.props !== newProps || this.state.predictionData !== newState.predictionData;
+ },
+
+ render: function() {
+ if (this.state.status === "success") {
+ return ;
+ }
+
+ return ;
+ }
+
+});
+
+var DepartureBoard = React.createClass({
+
+ render: function() {
+ var predictionData = this.props.predictionData;
+ var station = predictionData.station();
+
+ var generatedPlatforms = station.platforms().map(function(platform) {
+ return (
+
+
{platform.name()}
+
+
+ );
+ });
+
+ // Heading does not account for circle line mapping, meh
+ return (
+
+
{station.name() + " " + predictionData.line()}
+ {generatedPlatforms}
+
+ );
+ }
+
+});
+
+var Trains = React.createClass({
+
+ render: function() {
+ var generatedTrains = this.props.trains.map(function(train) {
+ return (
+
+ {train.timeTo()} |
+ {train.destination()} |
+ {train.location()} |
+
+ );
+ });
+
+ return (
+
+
+
+ Time |
+ Destination |
+ Current location |
+
+
+
+ {generatedTrains}
+
+
+ );
+ }
+
+});
+
+var Notice = React.createClass({
+
+ statusText: function(status) {
+ var text;
+
+ switch (status) {
+ case "error":
+ text = "Sorry an error occured, please try again.";
+ break;
+ case "loading":
+ text = "Loading predictions…"
+ break;
+ case "welcome":
+ text = "Please choose a station.";
+ break;
+ }
+
+ return text;
+ },
+
+ render: function() {
+ return (
+
+
{this.statusText(this.props.type)}
+
+ );
+ }
+
+});
diff --git a/app/component/tube-tracker.jsx b/app/component/tube-tracker.jsx
new file mode 100644
index 0000000..1ed045b
--- /dev/null
+++ b/app/component/tube-tracker.jsx
@@ -0,0 +1,64 @@
+/** @jsx React.DOM */
+var TubeTracker = React.createClass({
+
+ validateUserInput: function(line, station) {
+ return /^[A-Z]$/.test(line) && /^[A-Z]{3}$/.test(station) &&
+ utils.isStationOnLine(line, station, this.props.networkData);
+ },
+
+ formatAndValidateUserInput: function(userLine, userStation) {
+ var line = null;
+ var station = null;
+
+ // We could have added extra states for invalid data
+ // but it's easier simply to ignore it.
+ if (this.validateUserInput(userLine, userStation)) {
+ line = userLine;
+ station = userStation;
+ }
+
+ return {
+ line: line,
+ station: station
+ };
+ },
+
+ getInitialState: function() {
+ return this.formatAndValidateUserInput(
+ utils.queryStringProperty(utils.getQueryString(), "line"),
+ utils.queryStringProperty(utils.getQueryString(), "station")
+ );
+ },
+
+ handleUpdate: function(e) {
+ this.setState(this.formatAndValidateUserInput(e.detail.line, e.detail.station));
+ },
+
+ componentWillUpdate: function(newProps, newState) {
+ // When the state changes push a query string so users can bookmark
+ // or share the link to a chosen departure board.
+ window.history.pushState(null, null, utils.formatQueryString(newState));
+ },
+
+ componentWillMount: function() {
+ window.addEventListener("tt:update", this.handleUpdate, false);
+ },
+
+ componentWillUnmount: function() {
+ window.removeEventListener("tt:update", this.handleUpdate, false);
+ },
+
+ render: function() {
+ return (
+
+ );
+ }
+
+});
diff --git a/app/data.js b/app/data.js
new file mode 100644
index 0000000..ea9325b
--- /dev/null
+++ b/app/data.js
@@ -0,0 +1,596 @@
+var data = {};
+
+data.lines = {
+ "B": "Bakerloo",
+ "C": "Central",
+ "O": "Circle",
+ "D": "District",
+ "H": "Hammersmith & Circle",
+ "J": "Jubilee",
+ "M": "Metropolitan",
+ "N": "Northern",
+ "P": "Piccadilly",
+ "V": "Victoria",
+ "W": "Waterloo & City"
+};
+
+/*
+Stations missing from TfL's TrackerNet:
+- Bayswater
+- Chesham
+- Goldhawk Road
+- Ladbroke Grove
+- Latimer Road
+- Paddington Circle/District Line
+- Preston Road
+- Royal Oak
+- Shepherd's Bush Market
+- Westbourne Park
+- Wood Lane
+*/
+data.stations = {
+ "BST": "Baker Street",
+ "CHX": "Charing Cross",
+ "ERB": "Edgware Road (Bakerloo)",
+ "ELE": "Elephant and Castle",
+ "EMB": "Embankment",
+ "HSD": "Harlesden",
+ "HAW": "Harrow and Wealdstone",
+ "KGN": "Kensal Green",
+ "KNT": "Kenton",
+ "KPK": "Kilburn Park",
+ "LAM": "Lambeth North",
+ "MDV": "Maida Vale",
+ "MYB": "Marylebone",
+ "NWM": "North Wembley",
+ "OXC": "Oxford Circus",
+ "PAD": "Paddington",
+ "PIC": "Piccadilly Circus",
+ "QPK": "Queen's Park",
+ "RPK": "Regent's Park",
+ "SKT": "South Kenton",
+ "SPK": "Stonebridge Park",
+ "WAR": "Warwick Avenue",
+ "WLO": "Waterloo",
+ "WEM": "Wembley Central",
+ "WJN": "Willesden Junction",
+ "BNK": "Bank",
+ "BDE": "Barkingside",
+ "BNG": "Bethnal Green",
+ "BDS": "Bond Street",
+ "BHL": "Buckhurst Hill",
+ "CYL": "Chancery Lane",
+ "CHG": "Chigwell",
+ "DEB": "Debden",
+ "EBY": "Ealing Broadway",
+ "EAC": "East Acton",
+ "EPP": "Epping",
+ "FLP": "Fairlop",
+ "GHL": "Gants Hill",
+ "GRH": "Grange Hill",
+ "GFD": "Greenford",
+ "HAI": "Hainault",
+ "HLN": "Hanger Lane",
+ "HOL": "Holborn",
+ "HPK": "Holland Park",
+ "LAN": "Lancaster Gate",
+ "LEY": "Leyton",
+ "LYS": "Leytonstone",
+ "LST": "Liverpool Street",
+ "LTN": "Loughton",
+ "MAR": "Marble Arch",
+ "MLE": "Mile End",
+ "NEP": "Newbury Park",
+ "NAC": "North Acton",
+ "NHT": "Northolt",
+ "NHG": "Notting Hill Gate",
+ "PER": "Perivale",
+ "QWY": "Queensway",
+ "RED": "Redbridge",
+ "ROD": "Roding Valley",
+ "RUG": "Ruislip Gardens",
+ "SBC": "Shepherd's Bush",
+ "SNB": "Snaresbrook",
+ "SRP": "South Ruislip",
+ "SWF": "South Woodford",
+ "STP": "St Paul's",
+ "SFD": "Stratford",
+ "THB": "Theydon Bois",
+ "TCR": "Tottenham Court Road",
+ "WAN": "Wanstead",
+ "WAC": "West Acton",
+ "WRP": "West Ruislip",
+ "WCT": "White City",
+ "WFD": "Woodford",
+ "ACT": "Acton Town",
+ "ALE": "Aldgate East",
+ "BKG": "Barking",
+ "BCT": "Barons Court",
+ "BEC": "Becontree",
+ "BLF": "Blackfriars",
+ "BWR": "Bow Road",
+ "BBB": "Bromley-by-Bow",
+ "CST": "Cannon Street",
+ "CHP": "Chiswick Park",
+ "DGE": "Dagenham East",
+ "DGH": "Dagenham Heathway",
+ "ECM": "Ealing Common",
+ "ECT": "Earl's Court",
+ "EHM": "East Ham",
+ "EPY": "East Putney",
+ "ERD": "Edgware Road (H & C)",
+ "EPK": "Elm Park",
+ "FBY": "Fulham Broadway",
+ "GRD": "Gloucester Road",
+ "GUN": "Gunnersbury",
+ "HMD": "Hammersmith (District and Picc)",
+ "HST": "High Street Kensington",
+ "HCH": "Hornchurch",
+ "OLY": "Kensington (Olympia)",
+ "KEW": "Kew Gardens",
+ "MAN": "Mansion House",
+ "MON": "Monument",
+ "PGR": "Parsons Green",
+ "PLW": "Plaistow",
+ "PUT": "Putney Bridge",
+ "RCP": "Ravenscourt Park",
+ "RMD": "Richmond",
+ "SSQ": "Sloane Square",
+ "SKN": "South Kensington",
+ "SFS": "Southfields",
+ "SJP": "St. James's Park",
+ "STB": "Stamford Brook",
+ "STG": "Stepney Green",
+ "TEM": "Temple",
+ "THL": "Tower Hill",
+ "TGR": "Turnham Green",
+ "UPM": "Upminster",
+ "UPB": "Upminster Bridge",
+ "UPY": "Upney",
+ "UPK": "Upton Park",
+ "VIC": "Victoria",
+ "WBT": "West Brompton",
+ "WHM": "West Ham",
+ "WKN": "West Kensington",
+ "WMS": "Westminster",
+ "WCL": "Whitechapel",
+ "WDN": "Wimbledon",
+ "WMP": "Wimbledon Park",
+ "ALD": "Aldgate",
+ "BAR": "Barbican",
+ "ESQ": "Euston Square",
+ "FAR": "Farringdon",
+ "GPS": "Great Portland Street",
+ "HMS": "Hammersmith",
+ "KXX": "King's Cross St Pancras",
+ "MGT": "Moorgate",
+ "BER": "Bermondsey",
+ "CWR": "Canada Water",
+ "CWF": "Canary Wharf",
+ "CNT": "Canning Town",
+ "CPK": "Canons Park",
+ "DHL": "Dollis Hill",
+ "FRD": "Finchley Road",
+ "GPK": "Green Park",
+ "KIL": "Kilburn",
+ "KBY": "Kingsbury",
+ "LON": "London Bridge",
+ "NEA": "Neasden",
+ "NGW": "North Greenwich",
+ "QBY": "Queensbury",
+ "SWK": "Southwark",
+ "SJW": "St John's Wood",
+ "STA": "Stanmore",
+ "SWC": "Swiss Cottage",
+ "WPK": "Wembley Park",
+ "WHD": "West Hampstead",
+ "WLG": "Willesden Green",
+ "AME": "Amersham",
+ "CLF": "Chalfont and Latimer",
+ "CWD": "Chorleywood",
+ "CLW": "Colliers Wood",
+ "CRX": "Croxley",
+ "ETE": "Eastcote",
+ "HOH": "Harrow on the Hill",
+ "HDN": "Hillingdon",
+ "ICK": "Ickenham",
+ "MPK": "Moor Park",
+ "NHR": "North Harrow",
+ "NWP": "Northwick Park",
+ "NWD": "Northwood",
+ "NWH": "Northwood Hills",
+ "PIN": "Pinner",
+ "RLN": "Rayners Lane",
+ "RKY": "Rickmansworth",
+ "RUI": "Ruislip",
+ "RUM": "Ruislip Manor",
+ "UXB": "Uxbridge",
+ "WAT": "Watford",
+ "WHR": "West Harrow",
+ "ANG": "Angel",
+ "ARC": "Archway",
+ "BAL": "Balham",
+ "BPK": "Belsize Park",
+ "BOR": "Borough",
+ "BTX": "Brent Cross",
+ "BUR": "Burnt Oak",
+ "CTN": "Camden Town",
+ "CHF": "Chalk Farm",
+ "CPC": "Clapham Common",
+ "CPN": "Clapham North",
+ "CPS": "Clapham South",
+ "COL": "Colindale",
+ "EFY": "East Finchley",
+ "EDG": "Edgware",
+ "EUS": "Euston",
+ "FYC": "Finchley Central",
+ "GGR": "Golders Green",
+ "GST": "Goodge Street",
+ "HMP": "Hampstead",
+ "HND": "Hendon Central",
+ "HBT": "High Barnet",
+ "HIG": "Highgate",
+ "KEN": "Kennington",
+ "KTN": "Kentish Town",
+ "LSQ": "Leicester Square",
+ "MHE": "Mill Hill East",
+ "MOR": "Morden",
+ "MCR": "Mornington Crescent",
+ "OLD": "Old Street",
+ "OVL": "Oval",
+ "SWM": "South Wimbledon",
+ "STK": "Stockwell",
+ "TBE": "Tooting Bec",
+ "TBY": "Tooting Broadway",
+ "TOT": "Totteridge and Whetstone",
+ "TPK": "Tufnell Park",
+ "WST": "Warren Street",
+ "WFY": "West Finchley",
+ "WSP": "Woodside Park",
+ "ALP": "Alperton",
+ "AGR": "Arnos Grove",
+ "ARL": "Arsenal",
+ "BOS": "Boston Manor",
+ "BGR": "Bounds Green",
+ "CRD": "Caledonian Road",
+ "CFS": "Cockfosters",
+ "COV": "Covent Garden",
+ "FPK": "Finsbury Park",
+ "HTX": "Hatton Cross",
+ "HTF": "Heathrow Terminal 4",
+ "HRV": "Heathrow Terminal 5",
+ "HRC": "Heathrow Terminals 123",
+ "HRD": "Holloway Road",
+ "HNC": "Hounslow Central",
+ "HNE": "Hounslow East",
+ "HNW": "Hounslow West",
+ "HPC": "Hyde Park Corner",
+ "KNB": "Knightsbridge",
+ "MNR": "Manor House",
+ "NEL": "North Ealing",
+ "NFD": "Northfields",
+ "OAK": "Oakwood",
+ "OST": "Osterley",
+ "PRY": "Park Royal",
+ "RSQ": "Russell Square",
+ "SEL": "South Ealing",
+ "SHR": "South Harrow",
+ "SGT": "Southgate",
+ "SHL": "Sudbury Hill",
+ "STN": "Sudbury Town",
+ "TPL": "Turnpike Lane",
+ "WGN": "Wood Green",
+ "BHR": "Blackhorse Road",
+ "BRX": "Brixton",
+ "HBY": "Highbury and Islington",
+ "PIM": "Pimlico",
+ "SVS": "Seven Sisters",
+ "TTH": "Tottenham Hale",
+ "VUX": "Vauxhall",
+ "WAL": "Walthamstow Central"
+};
+
+data.stationsOnLines = {
+ "B": ["BST", "CHX", "ERB", "ELE", "EMB", "HSD", "HAW", "KGN", "KNT", "KPK", "LAM", "MDV", "MYB", "NWM", "OXC", "PAD", "PIC", "QPK", "RPK", "SKT", "SPK", "WAR", "WLO", "WEM", "WJN"],
+ "C": ["BNK", "BDE", "BNG", "BDS", "BHL", "CYL", "CHG", "DEB", "EBY", "EAC", "EPP", "FLP", "GHL", "GRH", "GFD", "HAI", "HLN", "HOL", "HPK", "LAN", "LEY", "LYS", "LST", "LTN", "MAR", "MLE", "NEP", "NAC", "NHT", "NHG", "OXC", "PER", "QWY", "RED", "ROD", "RUG", "SBC", "SNB", "SRP", "SWF", "STP", "SFD", "THB", "TCR", "WAN", "WAC", "WRP", "WCT", "WFD"],
+ "O": ["ALD", "BAR", "BLF", "BST", "CST", "EMB", "ERD", "ESQ", "FAR", "GPS", "GRD", "HMS", "HST", "KXX", "LST", "MAN", "MGT", "MON", "NHG", "SJP", "SKN", "SSQ", "TEM", "THL", "VIC", "WMS"],
+ "D": ["ACT", "ALE", "BKG", "BCT", "BEC", "BLF", "BWR", "BBB", "CST", "CHP", "DGE", "DGH", "EBY", "ECM", "ECT", "EHM", "EPY", "ERD", "EPK", "EMB", "FBY", "GRD", "GUN", "HMD", "HST", "HCH", "OLY", "KEW", "MAN", "MLE", "MON", "OLY", "PGR", "PLW", "PUT", "RCP", "RMD", "SSQ", "SKN", "SFS", "SJP", "STB", "STG", "TEM", "THL", "TGR", "UPM", "UPB", "UPY", "UPK", "VIC", "WBT", "WHM", "WKN", "WMS", "WCL", "WDN", "WMP"],
+ "H": ["ALD", "ALE", "BST", "BAR", "BKG", "BLF", "BWR", "BBB", "CST", "EHM", "ERD", "EMB", "ESQ", "FAR", "GRD", "GPS", "HMS", "HST", "KXX", "LST", "MAN", "MLE", "MON", "MGT", "PAD", "PLW", "SSQ", "SKN", "SJP", "STG", "TEM", "THL", "UPK", "VIC", "WHM", "WMS", "WCL"],
+ "J": ["BST", "BER", "BDS", "CWR", "CWF", "CNT", "CPK", "DHL", "FRD", "GPK", "KIL", "KBY", "LON", "NEA", "NGW", "QBY", "SWK", "SJW", "STA", "SFD", "SWC", "WLO", "WPK", "WHM", "WHD", "WMS", "WLG"],
+ "M": ["ALD", "AME", "BST", "BAR", "CLF", "CWD", "CLW", "CRX", "ETE", "ESQ", "FAR", "FRD", "GPS", "HOH", "HDN", "ICK", "KXX", "LST", "MPK", "MGT", "NHR", "NWP", "NWD", "NWH", "PIN", "RLN", "RKY", "RUI", "RUM", "UXB", "WAT", "WPK", "WHR"],
+ "N": ["ANG", "ARC", "BAL", "BNK", "BPK", "BOR", "BTX", "BUR", "CTN", "CHF", "CHX", "CPC", "CPN", "CPS", "COL", "CLW", "EFY", "EDG", "ELE", "EMB", "EUS", "FYC", "GGR", "GST", "HMP", "HND", "HBT", "HIG", "KEN", "KTN", "KXX", "LSQ", "LON", "MHE", "MGT", "MOR", "MCR", "OLD", "OVL", "SWM", "STK", "TBE", "TBY", "TCR", "TOT", "TPK", "WST", "WLO", "WFY", "WSP"],
+ "P": ["ACT", "ALP", "AGR", "ARL", "BCT", "BOS", "BGR", "CRD", "CFS", "COV", "ECM", "ECT", "ETE", "FPK", "GRD", "GPK", "HMD", "HTX", "HTF", "HRV", "HRC", "HDN", "HOL", "HRD", "HNC", "HNE", "HNW", "HPC", "ICK", "KXX", "KNB", "LSQ", "MNR", "NEL", "NFD", "OAK", "OST", "PRY", "PIC", "RLN", "RUI", "RUM", "RSQ", "SEL", "SHR", "SKN", "SGT", "SHL", "STN", "TGR", "TPL", "UXB", "WGN"],
+ "V": ["BHR", "BRX", "EUS", "FPK", "GPK", "HBY", "KXX", "OXC", "PIM", "SVS", "STK", "TTH", "VUX", "VIC", "WAL", "WST"],
+ "W": ["BNK", "WLO"]
+};
+
+data.circleLineMap = {
+ "ALD": "M",
+ "BAR": "H",
+ "BLF": "D",
+ "BST": "H",
+ "CST": "D",
+ "EMB": "D",
+ "ERD": "H",
+ "ESQ": "H",
+ "FAR": "H",
+ "GPS": "H",
+ "GRD": "D",
+ "HMS": "H",
+ "HST": "D",
+ "KXX": "H",
+ "LST": "H",
+ "MAN": "D",
+ "MGT": "H",
+ "MON": "D",
+ "NHG": "D",
+ "SJP": "D",
+ "SKN": "D",
+ "SSQ": "D",
+ "TEM": "D",
+ "THL": "D",
+ "VIC": "D",
+ "WMS": "D"
+};
+
+data.linesAtStations = {
+ "BST": ["B", "H", "J", "M"],
+ "CHX": ["B", "N"],
+ "ERB": ["B"],
+ "ELE": ["B", "N"],
+ "EMB": ["B", "D", "H", "N"],
+ "HSD": ["B"],
+ "HAW": ["B"],
+ "KGN": ["B"],
+ "KNT": ["B"],
+ "KPK": ["B"],
+ "LAM": ["B"],
+ "MDV": ["B"],
+ "MYB": ["B"],
+ "NWM": ["B"],
+ "OXC": ["B", "C", "V"],
+ "PAD": ["B", "H"],
+ "PIC": ["B", "P"],
+ "QPK": ["B"],
+ "RPK": ["B"],
+ "SKT": ["B"],
+ "SPK": ["B"],
+ "WAR": ["B"],
+ "WLO": ["B", "J", "N", "W"],
+ "WEM": ["B"],
+ "WJN": ["B"],
+ "BNK": ["C", "N", "W"],
+ "BDE": ["C"],
+ "BNG": ["C"],
+ "BDS": ["C", "J"],
+ "BHL": ["C"],
+ "CYL": ["C"],
+ "CHG": ["C"],
+ "DEB": ["C"],
+ "EBY": ["C", "D"],
+ "EAC": ["C"],
+ "EPP": ["C"],
+ "FLP": ["C"],
+ "GHL": ["C"],
+ "GRH": ["C"],
+ "GFD": ["C"],
+ "HAI": ["C"],
+ "HLN": ["C"],
+ "HOL": ["C", "P"],
+ "HPK": ["C"],
+ "LAN": ["C"],
+ "LEY": ["C"],
+ "LYS": ["C"],
+ "LST": ["C", "H", "M"],
+ "LTN": ["C"],
+ "MAR": ["C"],
+ "MLE": ["C", "D", "H"],
+ "NEP": ["C"],
+ "NAC": ["C"],
+ "NHT": ["C"],
+ "NHG": ["C"],
+ "PER": ["C"],
+ "QWY": ["C"],
+ "RED": ["C"],
+ "ROD": ["C"],
+ "RUG": ["C"],
+ "SBC": ["C"],
+ "SNB": ["C"],
+ "SRP": ["C"],
+ "SWF": ["C"],
+ "STP": ["C"],
+ "SFD": ["C", "J"],
+ "THB": ["C"],
+ "TCR": ["C", "N"],
+ "WAN": ["C"],
+ "WAC": ["C"],
+ "WRP": ["C"],
+ "WCT": ["C"],
+ "WFD": ["C"],
+ "ACT": ["D", "P"],
+ "ALE": ["D", "H"],
+ "BKG": ["D", "H"],
+ "BCT": ["D", "P"],
+ "BEC": ["D"],
+ "BLF": ["D", "H"],
+ "BWR": ["D", "H"],
+ "BBB": ["D", "H"],
+ "CST": ["D", "H"],
+ "CHP": ["D"],
+ "DGE": ["D"],
+ "DGH": ["D"],
+ "ECM": ["D", "P"],
+ "ECT": ["D", "P"],
+ "EHM": ["D", "H"],
+ "EPY": ["D"],
+ "ERD": ["D", "H"],
+ "EPK": ["D"],
+ "FBY": ["D"],
+ "GRD": ["D", "H", "P"],
+ "GUN": ["D"],
+ "HMD": ["D", "P"],
+ "HST": ["D", "H"],
+ "HCH": ["D"],
+ "OLY": ["D"],
+ "KEW": ["D"],
+ "MAN": ["D", "H"],
+ "MON": ["D", "H"],
+ "PGR": ["D"],
+ "PLW": ["D", "H"],
+ "PUT": ["D"],
+ "RCP": ["D"],
+ "RMD": ["D"],
+ "SSQ": ["D", "H"],
+ "SKN": ["D", "H", "P"],
+ "SFS": ["D"],
+ "SJP": ["D", "H"],
+ "STB": ["D"],
+ "STG": ["D", "H"],
+ "TEM": ["D", "H"],
+ "THL": ["D", "H"],
+ "TGR": ["D", "P"],
+ "UPM": ["D"],
+ "UPB": ["D"],
+ "UPY": ["D"],
+ "UPK": ["D", "H"],
+ "VIC": ["D", "H", "V"],
+ "WBT": ["D"],
+ "WHM": ["D", "H", "J"],
+ "WKN": ["D"],
+ "WMS": ["D", "H", "J"],
+ "WCL": ["D", "H"],
+ "WDN": ["D"],
+ "WMP": ["D"],
+ "ALD": ["H", "M"],
+ "BAR": ["H", "M"],
+ "ESQ": ["H", "M"],
+ "FAR": ["H", "M"],
+ "GPS": ["H", "M"],
+ "HMS": ["H"],
+ "KXX": ["H", "M", "N", "P", "V"],
+ "MGT": ["H", "M", "N"],
+ "BER": ["J"],
+ "CWR": ["J"],
+ "CWF": ["J"],
+ "CNT": ["J"],
+ "CPK": ["J"],
+ "DHL": ["J"],
+ "FRD": ["J", "M"],
+ "GPK": ["J", "P", "V"],
+ "KIL": ["J"],
+ "KBY": ["J"],
+ "LON": ["J", "N"],
+ "NEA": ["J"],
+ "NGW": ["J"],
+ "QBY": ["J"],
+ "SWK": ["J"],
+ "SJW": ["J"],
+ "STA": ["J"],
+ "SWC": ["J"],
+ "WPK": ["J", "M"],
+ "WHD": ["J"],
+ "WLG": ["J"],
+ "AME": ["M"],
+ "CLF": ["M"],
+ "CWD": ["M"],
+ "CLW": ["M", "N"],
+ "CRX": ["M"],
+ "ETE": ["M", "P"],
+ "HOH": ["M"],
+ "HDN": ["M", "P"],
+ "ICK": ["M", "P"],
+ "MPK": ["M"],
+ "NHR": ["M"],
+ "NWP": ["M"],
+ "NWD": ["M"],
+ "NWH": ["M"],
+ "PIN": ["M"],
+ "RLN": ["M", "P"],
+ "RKY": ["M"],
+ "RUI": ["M", "P"],
+ "RUM": ["M", "P"],
+ "UXB": ["M", "P"],
+ "WAT": ["M"],
+ "WHR": ["M"],
+ "ANG": ["N"],
+ "ARC": ["N"],
+ "BAL": ["N"],
+ "BPK": ["N"],
+ "BOR": ["N"],
+ "BTX": ["N"],
+ "BUR": ["N"],
+ "CTN": ["N"],
+ "CHF": ["N"],
+ "CPC": ["N"],
+ "CPN": ["N"],
+ "CPS": ["N"],
+ "COL": ["N"],
+ "EFY": ["N"],
+ "EDG": ["N"],
+ "EUS": ["N", "V"],
+ "FYC": ["N"],
+ "GGR": ["N"],
+ "GST": ["N"],
+ "HMP": ["N"],
+ "HND": ["N"],
+ "HBT": ["N"],
+ "HIG": ["N"],
+ "KEN": ["N"],
+ "KTN": ["N"],
+ "LSQ": ["N", "P"],
+ "MHE": ["N"],
+ "MOR": ["N"],
+ "MCR": ["N"],
+ "OLD": ["N"],
+ "OVL": ["N"],
+ "SWM": ["N"],
+ "STK": ["N", "V"],
+ "TBE": ["N"],
+ "TBY": ["N"],
+ "TOT": ["N"],
+ "TPK": ["N"],
+ "WST": ["N", "V"],
+ "WFY": ["N"],
+ "WSP": ["N"],
+ "ALP": ["P"],
+ "AGR": ["P"],
+ "ARL": ["P"],
+ "BOS": ["P"],
+ "BGR": ["P"],
+ "CRD": ["P"],
+ "CFS": ["P"],
+ "COV": ["P"],
+ "FPK": ["P", "V"],
+ "HTX": ["P"],
+ "HTF": ["P"],
+ "HRV": ["P"],
+ "HRC": ["P"],
+ "HRD": ["P"],
+ "HNC": ["P"],
+ "HNE": ["P"],
+ "HNW": ["P"],
+ "HPC": ["P"],
+ "KNB": ["P"],
+ "MNR": ["P"],
+ "NEL": ["P"],
+ "NFD": ["P"],
+ "OAK": ["P"],
+ "OST": ["P"],
+ "PRY": ["P"],
+ "RSQ": ["P"],
+ "SEL": ["P"],
+ "SHR": ["P"],
+ "SGT": ["P"],
+ "SHL": ["P"],
+ "STN": ["P"],
+ "TPL": ["P"],
+ "WGN": ["P"],
+ "BHR": ["V"],
+ "BRX": ["V"],
+ "HBY": ["V"],
+ "PIM": ["V"],
+ "SVS": ["V"],
+ "TTH": ["V"],
+ "VUX": ["V"],
+ "WAL": ["V"]
+};
diff --git a/app/model/platform.js b/app/model/platform.js
new file mode 100644
index 0000000..a04c089
--- /dev/null
+++ b/app/model/platform.js
@@ -0,0 +1,26 @@
+function Platform(data) {
+ this._raw = data;
+};
+
+Platform.prototype.name = function() {
+ return this._raw.getAttribute('N');
+};
+
+Platform.prototype.number = function() {
+ return this._raw.getAttribute('Num');
+};
+
+Platform.prototype.trains = function() {
+ var trains = [];
+ var nodes = this._raw.getElementsByTagName('T');
+
+ if (nodes.length > 5) {
+ nodes = Array.prototype.slice.call(nodes, 0, 5);
+ }
+
+ Array.prototype.forEach.call(nodes, function(node) {
+ trains.push(new Train(node));
+ });
+
+ return trains;
+};
diff --git a/app/model/prediction.js b/app/model/prediction.js
new file mode 100644
index 0000000..8c7ba26
--- /dev/null
+++ b/app/model/prediction.js
@@ -0,0 +1,13 @@
+function Prediction(xmlDoc) {
+ this._raw = xmlDoc;
+};
+
+Prediction.prototype.line = function() {
+ var nodes = this._raw.getElementsByTagName('LineName');
+ return nodes[0].textContent;
+};
+
+Prediction.prototype.station = function() {
+ var nodes = this._raw.getElementsByTagName('S');
+ return new Station(nodes[0]);
+};
diff --git a/app/model/station.js b/app/model/station.js
new file mode 100644
index 0000000..4cb2b13
--- /dev/null
+++ b/app/model/station.js
@@ -0,0 +1,18 @@
+function Station(data) {
+ this._raw = data;
+}
+
+Station.prototype.name = function() {
+ return this._raw.getAttribute('N');
+};
+
+Station.prototype.platforms = function() {
+ var platforms = [];
+ var nodes = this._raw.getElementsByTagName('P');
+
+ Array.prototype.forEach.call(nodes, function(node) {
+ platforms.push(new Platform(node));
+ });
+
+ return platforms;
+};
diff --git a/app/model/train.js b/app/model/train.js
new file mode 100644
index 0000000..6b19d7c
--- /dev/null
+++ b/app/model/train.js
@@ -0,0 +1,23 @@
+function Train(data) {
+ this._raw = data;
+};
+
+Train.prototype.id = function() {
+ return this._raw.getAttribute('LCID');
+};
+
+Train.prototype.timeTo = function() {
+ return this._raw.getAttribute('TimeTo');
+};
+
+Train.prototype.line = function() {
+ return this._raw.getAttribute('LN');
+};
+
+Train.prototype.location = function() {
+ return this._raw.getAttribute('Location');
+};
+
+Train.prototype.destination = function() {
+ return this._raw.getAttribute('Destination');
+};
diff --git a/app/utils.js b/app/utils.js
new file mode 100644
index 0000000..78ed3a8
--- /dev/null
+++ b/app/utils.js
@@ -0,0 +1,88 @@
+var utils = {
+
+ debounceEvent: function(callback, wait) {
+ var timeout;
+
+ return function() {
+ clearTimeout(timeout);
+ timeout = setTimeout(callback, wait);
+ };
+ },
+
+ httpRequest: function(url, success, error) {
+ var request = new XMLHttpRequest;
+
+ request.open("GET", url);
+
+ request.onload = function() {
+ if (this.status === 200) {
+ success(this.responseXML);
+ }
+ else {
+ error(new Error(this.status));
+ }
+ };
+
+ request.onerror = function() {
+ error(this.status);
+ };
+
+ request.send();
+ },
+
+ proxyRequestURL: function(url) {
+ var query = "select * from xml where url='" + url + "'";
+ return "http://query.yahooapis.com/v1/public/yql?q=" + encodeURIComponent(query);
+ },
+
+ validateResponse: function(responseDoc) {
+ return responseDoc.getElementsByTagName("S").length === 1;
+ },
+
+ getQueryString: function() {
+ return window.location.search.replace(/^\?/, "").replace(/\/$/, "");
+ },
+
+ formatQueryString: function(properties) {
+ var property;
+ var queryString = [];
+
+ for (property in properties) {
+ if (properties.hasOwnProperty(property)) {
+ queryString.push("" + property + "=" + properties[property]);
+ }
+ }
+
+ return "?" + queryString.join("&");
+ },
+
+ queryStringProperty: function(queryString, prop) {
+ var pairs = queryString.split("&");
+ var properties = {};
+
+ pairs.forEach(function(pair) {
+ pair = pair.split("=");
+ properties[ pair[0] ] = pair[1];
+ });
+
+ return properties[prop];
+ },
+
+ isLine: function(line, data) {
+ return line in data.lines;
+ },
+
+ isStation: function(station, data) {
+ return station in data.stations;
+ },
+
+ isStationOnLine: function(line, station, data) {
+ return this.isLine(line, data) && this.isStation(station, data) &&
+ data.stationsOnLines[line].indexOf(station) >= 0;
+ },
+
+ mapCircleLineStation: function(station, data) {
+ return data.circleLineMap[station];
+ }
+
+};
diff --git a/bower.json b/bower.json
index 91a71d0..7f75a0e 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,7 @@
{
"name": "tube-tracker",
- "version": "0.0.0",
+ "version": "0.1.0",
"dependencies": {
- "react": "~0.8.0"
+ "react": "~0.9.0"
}
}
diff --git a/package.json b/package.json
index 15029e5..e4f3313 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,12 @@
{
"name": "tube-tracker",
- "version": "0.0.0",
+ "version": "0.1.0",
"devDependencies": {
+ },
+ "dependencies": {
+ "express": "3.x"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
}
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..bef7df7
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+ TfL London Underground
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/styles/styles.css b/public/styles/styles.css
new file mode 100644
index 0000000..a31feb2
--- /dev/null
+++ b/public/styles/styles.css
@@ -0,0 +1,376 @@
+@import url(webfont.css);
+
+/* Normalise elements */
+html,
+body {
+ margin: 0;
+}
+
+legend,
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+select,
+button {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0;
+ border-radius: 0;
+ font: inherit;
+ vertical-align: middle;
+}
+
+button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+
+/* Typography */
+body {
+ font: normal 16px/1.5 Karla, Helvetica, Arial, sans-serif;
+ color: #333;
+}
+
+h1 {
+ margin: 0 0 16px;
+ font-weight: normal;
+ font-size: 36px;
+ line-height: 48px;
+}
+
+h2 {
+ margin: 0 0 8px;
+ font-weight: normal;
+ font-size: 24px;
+ line-height: 32px;
+}
+
+p {
+ margin: 0 0 16px;
+}
+
+
+/* Form elements */
+select,
+button {
+ display: inline-block;
+ height: 48px;
+ padding: 12px 16px;
+ border: 1px solid #999;
+ line-height: 22px;
+ color: #555;
+}
+
+select:focus,
+button:focus {
+ outline: 2px solid #2070B0;
+}
+
+select {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+
+ /* Remove the dropdown arrow from FF. Dirty. */
+ text-indent: .01px;
+ text-overflow: ' ';
+
+ background-color: #FFF;
+ box-shadow: inset 0 2px rgba(0, 0, 0, .15);
+}
+
+select:focus {
+ color: #333;
+ border-color: #0036FF;
+}
+
+button {
+ background-color: #E5E9E8;
+ text-shadow: 0 1px #FFF;
+ box-shadow: inset 0 1px #FFF;
+}
+
+button:hover,
+button:focus {
+ background-color: #EFF1F1;
+}
+
+button:active {
+ border-color: #999;
+ background-color: #D2D6D6;
+ box-shadow: inset 0 2px rgba(0, 0, 0, .15);
+}
+
+
+/* App layout */
+.layout {
+ overflow: hidden;
+}
+
+.layout__sidebar {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 35%;
+}
+
+.layout__content {
+ margin-left: 35%;
+}
+
+@media screen and (max-width: 800px) {
+
+ .layout__sidebar {
+ width: auto;
+ }
+
+ .layout__content {
+ margin-left: 0;
+ }
+
+}
+
+@media screen and (min-width: 1200px) {
+
+ .layout__sidebar {
+ width: 25%;
+ }
+
+ .layout__content {
+ margin-left: 25%;
+ }
+
+}
+
+
+/* Network panel */
+.network {
+ position: relative;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ min-height: 100%;
+ padding: 20px;
+ border-right: 1px solid #9daca9;
+ background: #FFF;
+}
+
+.network__line {
+ position: relative;
+ margin-bottom: 12px;
+ padding: 30px 10px 10px 20px;
+ border-left: 6px solid;
+}
+
+.network__line--b {
+ border-left-color: #894E24;
+}
+
+.network__line--c {
+ border-left-color: #DC241F;
+}
+
+.network__line--o {
+ border-left-color: #FFCE00;
+}
+
+.network__line--d {
+ border-left-color: #007229;
+}
+
+.network__line--h {
+ border-left-color: #D799AF;
+}
+
+.network__line--j {
+ border-left-color: #6A7278;
+}
+
+.network__line--m {
+ border-left-color: #751056;
+}
+
+.network__line--n {
+ border-left-color: #111;
+}
+
+.network__line--p {
+ border-left-color: #0019A8;
+}
+
+.network__line--v {
+ border-left-color: #00A0E2;
+}
+
+.network__line--w {
+ border-left-color: #76D0BD;
+}
+
+.network__line legend {
+ position: absolute;
+ top: 0;
+}
+
+.network__line select,
+.network__line button {
+ float: left;
+}
+
+.network__line select {
+ width: 75%;
+ border-right: 0;
+}
+
+.network__line button {
+ width: 25%;
+}
+
+.network__toggle {
+ display: none;
+}
+
+@media screen and (max-width: 800px) {
+
+ .network {
+ box-shadow: 0 0 5px rgba(0, 0, 0, .25);
+ }
+
+ .network.is-closed {
+ -webkit-transform: translate3d(-97.5%, 0, 0);
+ transform: translate3d(-97.5%, 0, 0);
+ }
+
+ .network.is-open {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ .network__toggle {
+ position: absolute;
+ top: 21px;
+ left: 100%;
+ display: inline-block;
+
+ /* Hide the text... */
+ overflow: hidden;
+ text-indent: -999px;
+ }
+
+ .network__toggle:after {
+ /* ... but display the generated content */
+ position: absolute;
+ left: 0;
+ width: 100%;
+ text-indent: 0;
+ text-align: center;
+ }
+
+ .is-closed .network__toggle:after {
+ content: " →";
+ }
+
+ .is-open .network__toggle:after {
+ content: " ←";
+ }
+
+}
+
+
+/* Departures */
+.departures {
+ padding: 20px;
+}
+
+.departures__heading {
+ overflow: hidden;
+ border-bottom: 1px solid #E0E0E0;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ color: #2070B0;
+ background: #FFF;
+}
+
+@media screen and (max-width: 800px) {
+
+ .departures {
+ /* Allow for network panel overlay */
+ padding-left: -webkit-calc(2.5% + 20px);
+ padding-left: calc(2.5% + 20px);
+ }
+
+ .departures__heading {
+ text-indent: 20px;
+ }
+
+}
+
+
+/* Trains */
+.trains {
+ width: 100%;
+ margin: 0 0 32px;
+ border: 1px solid #151717;
+ border-collapse: collapse;
+ color: #FFF;
+}
+
+.trains th,
+.trains td {
+ padding: 12px 16px;
+ text-align: left;
+}
+
+.trains th {
+ border-bottom: 1px solid #151717;
+ color: #FCFCBD;
+ background: #2D3232;
+ box-shadow: inset 0 2px rgba(255, 255, 255, .5);
+}
+
+.trains td {
+ border-bottom: 1px solid #2D3232;
+ background: #393F3F;
+ box-shadow: inset 0 2px rgba(255, 255, 255, .15);
+}
+
+@media screen and (max-width: 800px) {
+
+ .trains th:last-child,
+ .trains td:last-child {
+ display: none;
+ }
+
+}
+
+
+/* Notices */
+.notice {
+ margin: 20px;
+ padding: 20px;
+ border: 1px solid;
+ box-shadow: inset 0 2px #FFF;
+}
+
+.notice--welcome {
+ background: #F2F8FD;
+ border-color: #2B8BD8;
+}
+
+.notice--loading {
+ background: #FAFBFB;
+ border-color: #AEBDBD;
+}
+
+.notice--error {
+ background: #FDF2F2;
+ border-color: #D82B34;
+}
+
+.notice p {
+ margin-bottom: 0;
+}
diff --git a/public/styles/webfont.css b/public/styles/webfont.css
new file mode 100644
index 0000000..41a8199
--- /dev/null
+++ b/public/styles/webfont.css
@@ -0,0 +1,6 @@
+@font-face {
+ font-family: 'Karla';
+ src: url(data:application/x-font-woff;charset=utf-8;base64,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) format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..27e0402
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,23 @@
+# Tube Tracker
+
+This is a simple application to check the predicted arrival times of trains at stations on the London Underground network. It is built using [React][1] and the [TrackerNet API][2] from TfL. The application is being built in conjunction with my 3-part series "Building robust web apps with React":
+
+1. [In-browser prototype][part1] ([Download source code][tag1])
+2. Weaponising and testing (coming soon)
+3. Server hybrid (coming soon)
+
+## Dependencies
+
+- [Node.js and NPM](http://nodejs.org/)
+
+## Installation and usage
+
+1. Clone or download this repository
+2. Install dependencies with `npm install`
+3. Run `npm start` or `node server.js`
+4. Open your browser and navigate to `http://localhost:8080`
+
+[1]: http://facebook.github.io/react/
+[2]: http://www.tfl.gov.uk/businessandpartners/syndication/
+[part1]: http://maketea.co.uk/2014/03/05/building-robust-web-apps-with-react-part-1.html
+[tag1]: https://github.com/i-like-robots/tube-tracker/releases/tag/prototype
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..5c378fc
--- /dev/null
+++ b/server.js
@@ -0,0 +1,13 @@
+var express = require("express");
+var app = express();
+
+// Serve static assets
+app.use(express.static("./public"));
+app.use("/app", express.static("./app"));
+app.use("/vendor", express.static("./vendor"));
+
+var port = process.env.PORT || 8080;
+
+app.listen(port);
+
+console.log("Running server on port " + port + ", press ctrl + c to stop.");
diff --git a/vendor/react/.bower.json b/vendor/react/.bower.json
new file mode 100644
index 0000000..e25b452
--- /dev/null
+++ b/vendor/react/.bower.json
@@ -0,0 +1,15 @@
+{
+ "name": "react",
+ "version": "0.9.0",
+ "main": "react.js",
+ "homepage": "https://github.com/facebook/react-bower",
+ "_release": "0.9.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v0.9.0",
+ "commit": "81855fdf1b8454ee0ea8dd0e05a896cf5cf03010"
+ },
+ "_source": "git://github.com/facebook/react-bower.git",
+ "_target": "~0.9.0",
+ "_originalSource": "react"
+}
\ No newline at end of file
diff --git a/vendor/react/JSXTransformer.js b/vendor/react/JSXTransformer.js
new file mode 100644
index 0000000..1234541
--- /dev/null
+++ b/vendor/react/JSXTransformer.js
@@ -0,0 +1,12499 @@
+/**
+ * JSXTransformer v0.9.0
+ */
+!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.JSXTransformer=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) {
+ var fn = queue.shift();
+ fn();
+ }
+ }
+ }, true);
+
+ return function nextTick(fn) {
+ queue.push(fn);
+ window.postMessage('process-tick', '*');
+ };
+ }
+
+ return function nextTick(fn) {
+ setTimeout(fn, 0);
+ };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+}
+
+// TODO(shtylman)
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+
+},{}],2:[function(require,module,exports){
+var base64 = require('base64-js')
+var ieee754 = require('ieee754')
+
+exports.Buffer = Buffer
+exports.SlowBuffer = Buffer
+exports.INSPECT_MAX_BYTES = 50
+Buffer.poolSize = 8192
+
+/**
+ * If `Buffer._useTypedArrays`:
+ * === true Use Uint8Array implementation (fastest)
+ * === false Use Object implementation (compatible down to IE6)
+ */
+Buffer._useTypedArrays = (function () {
+ // Detect if browser supports Typed Arrays. Supported browsers are IE 10+,
+ // Firefox 4+, Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+.
+ if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined')
+ return false
+
+ // Does the browser support adding properties to `Uint8Array` instances? If
+ // not, then that's the same as no `Uint8Array` support. We need to be able to
+ // add all the node Buffer API methods.
+ // Relevant Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
+ try {
+ var arr = new Uint8Array(0)
+ arr.foo = function () { return 42 }
+ return 42 === arr.foo() &&
+ typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
+ } catch (e) {
+ return false
+ }
+})()
+
+/**
+ * Class: Buffer
+ * =============
+ *
+ * The Buffer constructor returns instances of `Uint8Array` that are augmented
+ * with function properties for all the node `Buffer` API functions. We use
+ * `Uint8Array` so that square bracket notation works as expected -- it returns
+ * a single octet.
+ *
+ * By augmenting the instances, we can avoid modifying the `Uint8Array`
+ * prototype.
+ */
+function Buffer (subject, encoding, noZero) {
+ if (!(this instanceof Buffer))
+ return new Buffer(subject, encoding, noZero)
+
+ var type = typeof subject
+
+ // Workaround: node's base64 implementation allows for non-padded strings
+ // while base64-js does not.
+ if (encoding === 'base64' && type === 'string') {
+ subject = stringtrim(subject)
+ while (subject.length % 4 !== 0) {
+ subject = subject + '='
+ }
+ }
+
+ // Find the length
+ var length
+ if (type === 'number')
+ length = coerce(subject)
+ else if (type === 'string')
+ length = Buffer.byteLength(subject, encoding)
+ else if (type === 'object')
+ length = coerce(subject.length) // Assume object is an array
+ else
+ throw new Error('First argument needs to be a number, array or string.')
+
+ var buf
+ if (Buffer._useTypedArrays) {
+ // Preferred: Return an augmented `Uint8Array` instance for best performance
+ buf = augment(new Uint8Array(length))
+ } else {
+ // Fallback: Return THIS instance of Buffer (created by `new`)
+ buf = this
+ buf.length = length
+ buf._isBuffer = true
+ }
+
+ var i
+ if (Buffer._useTypedArrays && typeof Uint8Array === 'function' &&
+ subject instanceof Uint8Array) {
+ // Speed optimization -- use set if we're copying from a Uint8Array
+ buf._set(subject)
+ } else if (isArrayish(subject)) {
+ // Treat array-ish objects as a byte array
+ for (i = 0; i < length; i++) {
+ if (Buffer.isBuffer(subject))
+ buf[i] = subject.readUInt8(i)
+ else
+ buf[i] = subject[i]
+ }
+ } else if (type === 'string') {
+ buf.write(subject, 0, encoding)
+ } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
+ for (i = 0; i < length; i++) {
+ buf[i] = 0
+ }
+ }
+
+ return buf
+}
+
+// STATIC METHODS
+// ==============
+
+Buffer.isEncoding = function (encoding) {
+ switch (String(encoding).toLowerCase()) {
+ case 'hex':
+ case 'utf8':
+ case 'utf-8':
+ case 'ascii':
+ case 'binary':
+ case 'base64':
+ case 'raw':
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return true
+ default:
+ return false
+ }
+}
+
+Buffer.isBuffer = function (b) {
+ return !!(b !== null && b !== undefined && b._isBuffer)
+}
+
+Buffer.byteLength = function (str, encoding) {
+ var ret
+ str = str + ''
+ switch (encoding || 'utf8') {
+ case 'hex':
+ ret = str.length / 2
+ break
+ case 'utf8':
+ case 'utf-8':
+ ret = utf8ToBytes(str).length
+ break
+ case 'ascii':
+ case 'binary':
+ case 'raw':
+ ret = str.length
+ break
+ case 'base64':
+ ret = base64ToBytes(str).length
+ break
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ ret = str.length * 2
+ break
+ default:
+ throw new Error('Unknown encoding')
+ }
+ return ret
+}
+
+Buffer.concat = function (list, totalLength) {
+ assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' +
+ 'list should be an Array.')
+
+ if (list.length === 0) {
+ return new Buffer(0)
+ } else if (list.length === 1) {
+ return list[0]
+ }
+
+ var i
+ if (typeof totalLength !== 'number') {
+ totalLength = 0
+ for (i = 0; i < list.length; i++) {
+ totalLength += list[i].length
+ }
+ }
+
+ var buf = new Buffer(totalLength)
+ var pos = 0
+ for (i = 0; i < list.length; i++) {
+ var item = list[i]
+ item.copy(buf, pos)
+ pos += item.length
+ }
+ return buf
+}
+
+// BUFFER INSTANCE METHODS
+// =======================
+
+function _hexWrite (buf, string, offset, length) {
+ offset = Number(offset) || 0
+ var remaining = buf.length - offset
+ if (!length) {
+ length = remaining
+ } else {
+ length = Number(length)
+ if (length > remaining) {
+ length = remaining
+ }
+ }
+
+ // must be an even number of digits
+ var strLen = string.length
+ assert(strLen % 2 === 0, 'Invalid hex string')
+
+ if (length > strLen / 2) {
+ length = strLen / 2
+ }
+ for (var i = 0; i < length; i++) {
+ var byte = parseInt(string.substr(i * 2, 2), 16)
+ assert(!isNaN(byte), 'Invalid hex string')
+ buf[offset + i] = byte
+ }
+ Buffer._charsWritten = i * 2
+ return i
+}
+
+function _utf8Write (buf, string, offset, length) {
+ var charsWritten = Buffer._charsWritten =
+ blitBuffer(utf8ToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+function _asciiWrite (buf, string, offset, length) {
+ var charsWritten = Buffer._charsWritten =
+ blitBuffer(asciiToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+function _binaryWrite (buf, string, offset, length) {
+ return _asciiWrite(buf, string, offset, length)
+}
+
+function _base64Write (buf, string, offset, length) {
+ var charsWritten = Buffer._charsWritten =
+ blitBuffer(base64ToBytes(string), buf, offset, length)
+ return charsWritten
+}
+
+Buffer.prototype.write = function (string, offset, length, encoding) {
+ // Support both (string, offset, length, encoding)
+ // and the legacy (string, encoding, offset, length)
+ if (isFinite(offset)) {
+ if (!isFinite(length)) {
+ encoding = length
+ length = undefined
+ }
+ } else { // legacy
+ var swap = encoding
+ encoding = offset
+ offset = length
+ length = swap
+ }
+
+ offset = Number(offset) || 0
+ var remaining = this.length - offset
+ if (!length) {
+ length = remaining
+ } else {
+ length = Number(length)
+ if (length > remaining) {
+ length = remaining
+ }
+ }
+ encoding = String(encoding || 'utf8').toLowerCase()
+
+ switch (encoding) {
+ case 'hex':
+ return _hexWrite(this, string, offset, length)
+ case 'utf8':
+ case 'utf-8':
+ case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return _utf8Write(this, string, offset, length)
+ case 'ascii':
+ return _asciiWrite(this, string, offset, length)
+ case 'binary':
+ return _binaryWrite(this, string, offset, length)
+ case 'base64':
+ return _base64Write(this, string, offset, length)
+ default:
+ throw new Error('Unknown encoding')
+ }
+}
+
+Buffer.prototype.toString = function (encoding, start, end) {
+ var self = this
+
+ encoding = String(encoding || 'utf8').toLowerCase()
+ start = Number(start) || 0
+ end = (end !== undefined)
+ ? Number(end)
+ : end = self.length
+
+ // Fastpath empty strings
+ if (end === start)
+ return ''
+
+ switch (encoding) {
+ case 'hex':
+ return _hexSlice(self, start, end)
+ case 'utf8':
+ case 'utf-8':
+ case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return _utf8Slice(self, start, end)
+ case 'ascii':
+ return _asciiSlice(self, start, end)
+ case 'binary':
+ return _binarySlice(self, start, end)
+ case 'base64':
+ return _base64Slice(self, start, end)
+ default:
+ throw new Error('Unknown encoding')
+ }
+}
+
+Buffer.prototype.toJSON = function () {
+ return {
+ type: 'Buffer',
+ data: Array.prototype.slice.call(this._arr || this, 0)
+ }
+}
+
+// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
+Buffer.prototype.copy = function (target, target_start, start, end) {
+ var source = this
+
+ if (!start) start = 0
+ if (!end && end !== 0) end = this.length
+ if (!target_start) target_start = 0
+
+ // Copy 0 bytes; we're done
+ if (end === start) return
+ if (target.length === 0 || source.length === 0) return
+
+ // Fatal error conditions
+ assert(end >= start, 'sourceEnd < sourceStart')
+ assert(target_start >= 0 && target_start < target.length,
+ 'targetStart out of bounds')
+ assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
+ assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
+
+ // Are we oob?
+ if (end > this.length)
+ end = this.length
+ if (target.length - target_start < end - start)
+ end = target.length - target_start + start
+
+ // copy!
+ for (var i = 0; i < end - start; i++)
+ target[i + target_start] = this[i + start]
+}
+
+function _base64Slice (buf, start, end) {
+ if (start === 0 && end === buf.length) {
+ return base64.fromByteArray(buf)
+ } else {
+ return base64.fromByteArray(buf.slice(start, end))
+ }
+}
+
+function _utf8Slice (buf, start, end) {
+ var res = ''
+ var tmp = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; i++) {
+ if (buf[i] <= 0x7F) {
+ res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
+ tmp = ''
+ } else {
+ tmp += '%' + buf[i].toString(16)
+ }
+ }
+
+ return res + decodeUtf8Char(tmp)
+}
+
+function _asciiSlice (buf, start, end) {
+ var ret = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; i++)
+ ret += String.fromCharCode(buf[i])
+ return ret
+}
+
+function _binarySlice (buf, start, end) {
+ return _asciiSlice(buf, start, end)
+}
+
+function _hexSlice (buf, start, end) {
+ var len = buf.length
+
+ if (!start || start < 0) start = 0
+ if (!end || end < 0 || end > len) end = len
+
+ var out = ''
+ for (var i = start; i < end; i++) {
+ out += toHex(buf[i])
+ }
+ return out
+}
+
+// http://nodejs.org/api/buffer.html#buffer_buf_slice_start_end
+Buffer.prototype.slice = function (start, end) {
+ var len = this.length
+ start = clamp(start, len, 0)
+ end = clamp(end, len, len)
+
+ if (Buffer._useTypedArrays) {
+ return augment(this.subarray(start, end))
+ } else {
+ var sliceLen = end - start
+ var newBuf = new Buffer(sliceLen, undefined, true)
+ for (var i = 0; i < sliceLen; i++) {
+ newBuf[i] = this[i + start]
+ }
+ return newBuf
+ }
+}
+
+// `get` will be removed in Node 0.13+
+Buffer.prototype.get = function (offset) {
+ console.log('.get() is deprecated. Access using array indexes instead.')
+ return this.readUInt8(offset)
+}
+
+// `set` will be removed in Node 0.13+
+Buffer.prototype.set = function (v, offset) {
+ console.log('.set() is deprecated. Access using array indexes instead.')
+ return this.writeUInt8(v, offset)
+}
+
+Buffer.prototype.readUInt8 = function (offset, noAssert) {
+ if (!noAssert) {
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset < this.length, 'Trying to read beyond buffer length')
+ }
+
+ if (offset >= this.length)
+ return
+
+ return this[offset]
+}
+
+function _readUInt16 (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ var val
+ if (littleEndian) {
+ val = buf[offset]
+ if (offset + 1 < len)
+ val |= buf[offset + 1] << 8
+ } else {
+ val = buf[offset] << 8
+ if (offset + 1 < len)
+ val |= buf[offset + 1]
+ }
+ return val
+}
+
+Buffer.prototype.readUInt16LE = function (offset, noAssert) {
+ return _readUInt16(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readUInt16BE = function (offset, noAssert) {
+ return _readUInt16(this, offset, false, noAssert)
+}
+
+function _readUInt32 (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ var val
+ if (littleEndian) {
+ if (offset + 2 < len)
+ val = buf[offset + 2] << 16
+ if (offset + 1 < len)
+ val |= buf[offset + 1] << 8
+ val |= buf[offset]
+ if (offset + 3 < len)
+ val = val + (buf[offset + 3] << 24 >>> 0)
+ } else {
+ if (offset + 1 < len)
+ val = buf[offset + 1] << 16
+ if (offset + 2 < len)
+ val |= buf[offset + 2] << 8
+ if (offset + 3 < len)
+ val |= buf[offset + 3]
+ val = val + (buf[offset] << 24 >>> 0)
+ }
+ return val
+}
+
+Buffer.prototype.readUInt32LE = function (offset, noAssert) {
+ return _readUInt32(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readUInt32BE = function (offset, noAssert) {
+ return _readUInt32(this, offset, false, noAssert)
+}
+
+Buffer.prototype.readInt8 = function (offset, noAssert) {
+ if (!noAssert) {
+ assert(offset !== undefined && offset !== null,
+ 'missing offset')
+ assert(offset < this.length, 'Trying to read beyond buffer length')
+ }
+
+ if (offset >= this.length)
+ return
+
+ var neg = this[offset] & 0x80
+ if (neg)
+ return (0xff - this[offset] + 1) * -1
+ else
+ return this[offset]
+}
+
+function _readInt16 (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ var val = _readUInt16(buf, offset, littleEndian, true)
+ var neg = val & 0x8000
+ if (neg)
+ return (0xffff - val + 1) * -1
+ else
+ return val
+}
+
+Buffer.prototype.readInt16LE = function (offset, noAssert) {
+ return _readInt16(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readInt16BE = function (offset, noAssert) {
+ return _readInt16(this, offset, false, noAssert)
+}
+
+function _readInt32 (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ var val = _readUInt32(buf, offset, littleEndian, true)
+ var neg = val & 0x80000000
+ if (neg)
+ return (0xffffffff - val + 1) * -1
+ else
+ return val
+}
+
+Buffer.prototype.readInt32LE = function (offset, noAssert) {
+ return _readInt32(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readInt32BE = function (offset, noAssert) {
+ return _readInt32(this, offset, false, noAssert)
+}
+
+function _readFloat (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ return ieee754.read(buf, offset, littleEndian, 23, 4)
+}
+
+Buffer.prototype.readFloatLE = function (offset, noAssert) {
+ return _readFloat(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readFloatBE = function (offset, noAssert) {
+ return _readFloat(this, offset, false, noAssert)
+}
+
+function _readDouble (buf, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
+ }
+
+ return ieee754.read(buf, offset, littleEndian, 52, 8)
+}
+
+Buffer.prototype.readDoubleLE = function (offset, noAssert) {
+ return _readDouble(this, offset, true, noAssert)
+}
+
+Buffer.prototype.readDoubleBE = function (offset, noAssert) {
+ return _readDouble(this, offset, false, noAssert)
+}
+
+Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset < this.length, 'trying to write beyond buffer length')
+ verifuint(value, 0xff)
+ }
+
+ if (offset >= this.length) return
+
+ this[offset] = value
+}
+
+function _writeUInt16 (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
+ verifuint(value, 0xffff)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
+ buf[offset + i] =
+ (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
+ (littleEndian ? i : 1 - i) * 8
+ }
+}
+
+Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
+ _writeUInt16(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
+ _writeUInt16(this, value, offset, false, noAssert)
+}
+
+function _writeUInt32 (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
+ verifuint(value, 0xffffffff)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
+ buf[offset + i] =
+ (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
+ }
+}
+
+Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
+ _writeUInt32(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
+ _writeUInt32(this, value, offset, false, noAssert)
+}
+
+Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset < this.length, 'Trying to write beyond buffer length')
+ verifsint(value, 0x7f, -0x80)
+ }
+
+ if (offset >= this.length)
+ return
+
+ if (value >= 0)
+ this.writeUInt8(value, offset, noAssert)
+ else
+ this.writeUInt8(0xff + value + 1, offset, noAssert)
+}
+
+function _writeInt16 (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
+ verifsint(value, 0x7fff, -0x8000)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ if (value >= 0)
+ _writeUInt16(buf, value, offset, littleEndian, noAssert)
+ else
+ _writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
+}
+
+Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
+ _writeInt16(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
+ _writeInt16(this, value, offset, false, noAssert)
+}
+
+function _writeInt32 (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
+ verifsint(value, 0x7fffffff, -0x80000000)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ if (value >= 0)
+ _writeUInt32(buf, value, offset, littleEndian, noAssert)
+ else
+ _writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
+}
+
+Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
+ _writeInt32(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
+ _writeInt32(this, value, offset, false, noAssert)
+}
+
+function _writeFloat (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
+ verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ ieee754.write(buf, value, offset, littleEndian, 23, 4)
+}
+
+Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
+ _writeFloat(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
+ _writeFloat(this, value, offset, false, noAssert)
+}
+
+function _writeDouble (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ assert(value !== undefined && value !== null, 'missing value')
+ assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
+ assert(offset !== undefined && offset !== null, 'missing offset')
+ assert(offset + 7 < buf.length,
+ 'Trying to write beyond buffer length')
+ verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
+ }
+
+ var len = buf.length
+ if (offset >= len)
+ return
+
+ ieee754.write(buf, value, offset, littleEndian, 52, 8)
+}
+
+Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
+ _writeDouble(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
+ _writeDouble(this, value, offset, false, noAssert)
+}
+
+// fill(value, start=0, end=buffer.length)
+Buffer.prototype.fill = function (value, start, end) {
+ if (!value) value = 0
+ if (!start) start = 0
+ if (!end) end = this.length
+
+ if (typeof value === 'string') {
+ value = value.charCodeAt(0)
+ }
+
+ assert(typeof value === 'number' && !isNaN(value), 'value is not a number')
+ assert(end >= start, 'end < start')
+
+ // Fill 0 bytes; we're done
+ if (end === start) return
+ if (this.length === 0) return
+
+ assert(start >= 0 && start < this.length, 'start out of bounds')
+ assert(end >= 0 && end <= this.length, 'end out of bounds')
+
+ for (var i = start; i < end; i++) {
+ this[i] = value
+ }
+}
+
+Buffer.prototype.inspect = function () {
+ var out = []
+ var len = this.length
+ for (var i = 0; i < len; i++) {
+ out[i] = toHex(this[i])
+ if (i === exports.INSPECT_MAX_BYTES) {
+ out[i + 1] = '...'
+ break
+ }
+ }
+ return ''
+}
+
+/**
+ * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
+ * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
+ */
+Buffer.prototype.toArrayBuffer = function () {
+ if (typeof Uint8Array === 'function') {
+ if (Buffer._useTypedArrays) {
+ return (new Buffer(this)).buffer
+ } else {
+ var buf = new Uint8Array(this.length)
+ for (var i = 0, len = buf.length; i < len; i += 1)
+ buf[i] = this[i]
+ return buf.buffer
+ }
+ } else {
+ throw new Error('Buffer.toArrayBuffer not supported in this browser')
+ }
+}
+
+// HELPER FUNCTIONS
+// ================
+
+function stringtrim (str) {
+ if (str.trim) return str.trim()
+ return str.replace(/^\s+|\s+$/g, '')
+}
+
+var BP = Buffer.prototype
+
+/**
+ * Augment the Uint8Array *instance* (not the class!) with Buffer methods
+ */
+function augment (arr) {
+ arr._isBuffer = true
+
+ // save reference to original Uint8Array get/set methods before overwriting
+ arr._get = arr.get
+ arr._set = arr.set
+
+ // deprecated, will be removed in node 0.13+
+ arr.get = BP.get
+ arr.set = BP.set
+
+ arr.write = BP.write
+ arr.toString = BP.toString
+ arr.toLocaleString = BP.toString
+ arr.toJSON = BP.toJSON
+ arr.copy = BP.copy
+ arr.slice = BP.slice
+ arr.readUInt8 = BP.readUInt8
+ arr.readUInt16LE = BP.readUInt16LE
+ arr.readUInt16BE = BP.readUInt16BE
+ arr.readUInt32LE = BP.readUInt32LE
+ arr.readUInt32BE = BP.readUInt32BE
+ arr.readInt8 = BP.readInt8
+ arr.readInt16LE = BP.readInt16LE
+ arr.readInt16BE = BP.readInt16BE
+ arr.readInt32LE = BP.readInt32LE
+ arr.readInt32BE = BP.readInt32BE
+ arr.readFloatLE = BP.readFloatLE
+ arr.readFloatBE = BP.readFloatBE
+ arr.readDoubleLE = BP.readDoubleLE
+ arr.readDoubleBE = BP.readDoubleBE
+ arr.writeUInt8 = BP.writeUInt8
+ arr.writeUInt16LE = BP.writeUInt16LE
+ arr.writeUInt16BE = BP.writeUInt16BE
+ arr.writeUInt32LE = BP.writeUInt32LE
+ arr.writeUInt32BE = BP.writeUInt32BE
+ arr.writeInt8 = BP.writeInt8
+ arr.writeInt16LE = BP.writeInt16LE
+ arr.writeInt16BE = BP.writeInt16BE
+ arr.writeInt32LE = BP.writeInt32LE
+ arr.writeInt32BE = BP.writeInt32BE
+ arr.writeFloatLE = BP.writeFloatLE
+ arr.writeFloatBE = BP.writeFloatBE
+ arr.writeDoubleLE = BP.writeDoubleLE
+ arr.writeDoubleBE = BP.writeDoubleBE
+ arr.fill = BP.fill
+ arr.inspect = BP.inspect
+ arr.toArrayBuffer = BP.toArrayBuffer
+
+ return arr
+}
+
+// slice(start, end)
+function clamp (index, len, defaultValue) {
+ if (typeof index !== 'number') return defaultValue
+ index = ~~index; // Coerce to integer.
+ if (index >= len) return len
+ if (index >= 0) return index
+ index += len
+ if (index >= 0) return index
+ return 0
+}
+
+function coerce (length) {
+ // Coerce length to a number (possibly NaN), round up
+ // in case it's fractional (e.g. 123.456) then do a
+ // double negate to coerce a NaN to 0. Easy, right?
+ length = ~~Math.ceil(+length)
+ return length < 0 ? 0 : length
+}
+
+function isArray (subject) {
+ return (Array.isArray || function (subject) {
+ return Object.prototype.toString.call(subject) === '[object Array]'
+ })(subject)
+}
+
+function isArrayish (subject) {
+ return isArray(subject) || Buffer.isBuffer(subject) ||
+ subject && typeof subject === 'object' &&
+ typeof subject.length === 'number'
+}
+
+function toHex (n) {
+ if (n < 16) return '0' + n.toString(16)
+ return n.toString(16)
+}
+
+function utf8ToBytes (str) {
+ var byteArray = []
+ for (var i = 0; i < str.length; i++) {
+ var b = str.charCodeAt(i)
+ if (b <= 0x7F)
+ byteArray.push(str.charCodeAt(i))
+ else {
+ var start = i
+ if (b >= 0xD800 && b <= 0xDFFF) i++
+ var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
+ for (var j = 0; j < h.length; j++)
+ byteArray.push(parseInt(h[j], 16))
+ }
+ }
+ return byteArray
+}
+
+function asciiToBytes (str) {
+ var byteArray = []
+ for (var i = 0; i < str.length; i++) {
+ // Node's code seems to be doing this and not & 0x7F..
+ byteArray.push(str.charCodeAt(i) & 0xFF)
+ }
+ return byteArray
+}
+
+function base64ToBytes (str) {
+ return base64.toByteArray(str)
+}
+
+function blitBuffer (src, dst, offset, length) {
+ var pos
+ for (var i = 0; i < length; i++) {
+ if ((i + offset >= dst.length) || (i >= src.length))
+ break
+ dst[i + offset] = src[i]
+ }
+ return i
+}
+
+function decodeUtf8Char (str) {
+ try {
+ return decodeURIComponent(str)
+ } catch (err) {
+ return String.fromCharCode(0xFFFD) // UTF 8 invalid char
+ }
+}
+
+/*
+ * We have to make sure that the value is a valid integer. This means that it
+ * is non-negative. It has no fractional component and that it does not
+ * exceed the maximum allowed value.
+ */
+function verifuint (value, max) {
+ assert(typeof value == 'number', 'cannot write a non-number as a number')
+ assert(value >= 0,
+ 'specified a negative value for writing an unsigned value')
+ assert(value <= max, 'value is larger than maximum value for type')
+ assert(Math.floor(value) === value, 'value has a fractional component')
+}
+
+function verifsint(value, max, min) {
+ assert(typeof value == 'number', 'cannot write a non-number as a number')
+ assert(value <= max, 'value larger than maximum allowed value')
+ assert(value >= min, 'value smaller than minimum allowed value')
+ assert(Math.floor(value) === value, 'value has a fractional component')
+}
+
+function verifIEEE754(value, max, min) {
+ assert(typeof value == 'number', 'cannot write a non-number as a number')
+ assert(value <= max, 'value larger than maximum allowed value')
+ assert(value >= min, 'value smaller than minimum allowed value')
+}
+
+function assert (test, message) {
+ if (!test) throw new Error(message || 'Failed assertion')
+}
+
+},{"base64-js":3,"ieee754":4}],3:[function(require,module,exports){
+var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+;(function (exports) {
+ 'use strict';
+
+ var Arr = (typeof Uint8Array !== 'undefined')
+ ? Uint8Array
+ : Array
+
+ var ZERO = '0'.charCodeAt(0)
+ var PLUS = '+'.charCodeAt(0)
+ var SLASH = '/'.charCodeAt(0)
+ var NUMBER = '0'.charCodeAt(0)
+ var LOWER = 'a'.charCodeAt(0)
+ var UPPER = 'A'.charCodeAt(0)
+
+ function decode (elt) {
+ var code = elt.charCodeAt(0)
+ if (code === PLUS)
+ return 62 // '+'
+ if (code === SLASH)
+ return 63 // '/'
+ if (code < NUMBER)
+ return -1 //no match
+ if (code < NUMBER + 10)
+ return code - NUMBER + 26 + 26
+ if (code < UPPER + 26)
+ return code - UPPER
+ if (code < LOWER + 26)
+ return code - LOWER + 26
+ }
+
+ function b64ToByteArray (b64) {
+ var i, j, l, tmp, placeHolders, arr
+
+ if (b64.length % 4 > 0) {
+ throw new Error('Invalid string. Length must be a multiple of 4')
+ }
+
+ // the number of equal signs (place holders)
+ // if there are two placeholders, than the two characters before it
+ // represent one byte
+ // if there is only one, then the three characters before it represent 2 bytes
+ // this is just a cheap hack to not do indexOf twice
+ var len = b64.length
+ placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
+
+ // base64 is 4/3 + up to two characters of the original data
+ arr = new Arr(b64.length * 3 / 4 - placeHolders)
+
+ // if there are placeholders, only get up to the last complete 4 chars
+ l = placeHolders > 0 ? b64.length - 4 : b64.length
+
+ var L = 0
+
+ function push (v) {
+ arr[L++] = v
+ }
+
+ for (i = 0, j = 0; i < l; i += 4, j += 3) {
+ tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
+ push((tmp & 0xFF0000) >> 16)
+ push((tmp & 0xFF00) >> 8)
+ push(tmp & 0xFF)
+ }
+
+ if (placeHolders === 2) {
+ tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
+ push(tmp & 0xFF)
+ } else if (placeHolders === 1) {
+ tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
+ push((tmp >> 8) & 0xFF)
+ push(tmp & 0xFF)
+ }
+
+ return arr
+ }
+
+ function uint8ToBase64 (uint8) {
+ var i,
+ extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
+ output = "",
+ temp, length
+
+ function encode (num) {
+ return lookup.charAt(num)
+ }
+
+ function tripletToBase64 (num) {
+ return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
+ }
+
+ // go through the array every three bytes, we'll deal with trailing stuff later
+ for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
+ temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
+ output += tripletToBase64(temp)
+ }
+
+ // pad the end with zeros, but make sure to not forget the extra bytes
+ switch (extraBytes) {
+ case 1:
+ temp = uint8[uint8.length - 1]
+ output += encode(temp >> 2)
+ output += encode((temp << 4) & 0x3F)
+ output += '=='
+ break
+ case 2:
+ temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
+ output += encode(temp >> 10)
+ output += encode((temp >> 4) & 0x3F)
+ output += encode((temp << 2) & 0x3F)
+ output += '='
+ break
+ }
+
+ return output
+ }
+
+ module.exports.toByteArray = b64ToByteArray
+ module.exports.fromByteArray = uint8ToBase64
+}())
+
+},{}],4:[function(require,module,exports){
+exports.read = function(buffer, offset, isLE, mLen, nBytes) {
+ var e, m,
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ nBits = -7,
+ i = isLE ? (nBytes - 1) : 0,
+ d = isLE ? -1 : 1,
+ s = buffer[offset + i];
+
+ i += d;
+
+ e = s & ((1 << (-nBits)) - 1);
+ s >>= (-nBits);
+ nBits += eLen;
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ m = e & ((1 << (-nBits)) - 1);
+ e >>= (-nBits);
+ nBits += mLen;
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ if (e === 0) {
+ e = 1 - eBias;
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity);
+ } else {
+ m = m + Math.pow(2, mLen);
+ e = e - eBias;
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
+};
+
+exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
+ var e, m, c,
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
+ i = isLE ? 0 : (nBytes - 1),
+ d = isLE ? 1 : -1,
+ s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
+
+ value = Math.abs(value);
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0;
+ e = eMax;
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2);
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--;
+ c *= 2;
+ }
+ if (e + eBias >= 1) {
+ value += rt / c;
+ } else {
+ value += rt * Math.pow(2, 1 - eBias);
+ }
+ if (value * c >= 2) {
+ e++;
+ c /= 2;
+ }
+
+ if (e + eBias >= eMax) {
+ m = 0;
+ e = eMax;
+ } else if (e + eBias >= 1) {
+ m = (value * c - 1) * Math.pow(2, mLen);
+ e = e + eBias;
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
+ e = 0;
+ }
+ }
+
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
+
+ e = (e << mLen) | m;
+ eLen += mLen;
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
+
+ buffer[offset + i - d] |= s * 128;
+};
+
+},{}],5:[function(require,module,exports){
+var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (; up--; up) {
+ parts.unshift('..');
+ }
+ }
+
+ return parts;
+}
+
+// Split a filename into [root, dir, basename, ext], unix version
+// 'root' is just a slash, or nothing.
+var splitPathRe =
+ /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+var splitPath = function(filename) {
+ return splitPathRe.exec(filename).slice(1);
+};
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+ var resolvedPath = '',
+ resolvedAbsolute = false;
+
+ for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? arguments[i] : process.cwd();
+
+ // Skip empty and invalid entries
+ if (typeof path !== 'string') {
+ throw new TypeError('Arguments to path.resolve must be strings');
+ } else if (!path) {
+ continue;
+ }
+
+ resolvedPath = path + '/' + resolvedPath;
+ resolvedAbsolute = path.charAt(0) === '/';
+ }
+
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+
+ // Normalize the path
+ resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
+ return !!p;
+ }), !resolvedAbsolute).join('/');
+
+ return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+ var isAbsolute = exports.isAbsolute(path),
+ trailingSlash = substr(path, -1) === '/';
+
+ // Normalize the path
+ path = normalizeArray(filter(path.split('/'), function(p) {
+ return !!p;
+ }), !isAbsolute).join('/');
+
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+
+ return (isAbsolute ? '/' : '') + path;
+};
+
+// posix version
+exports.isAbsolute = function(path) {
+ return path.charAt(0) === '/';
+};
+
+// posix version
+exports.join = function() {
+ var paths = Array.prototype.slice.call(arguments, 0);
+ return exports.normalize(filter(paths, function(p, index) {
+ if (typeof p !== 'string') {
+ throw new TypeError('Arguments to path.join must be strings');
+ }
+ return p;
+ }).join('/'));
+};
+
+
+// path.relative(from, to)
+// posix version
+exports.relative = function(from, to) {
+ from = exports.resolve(from).substr(1);
+ to = exports.resolve(to).substr(1);
+
+ function trim(arr) {
+ var start = 0;
+ for (; start < arr.length; start++) {
+ if (arr[start] !== '') break;
+ }
+
+ var end = arr.length - 1;
+ for (; end >= 0; end--) {
+ if (arr[end] !== '') break;
+ }
+
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+
+ var fromParts = trim(from.split('/'));
+ var toParts = trim(to.split('/'));
+
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push('..');
+ }
+
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+ return outputParts.join('/');
+};
+
+exports.sep = '/';
+exports.delimiter = ':';
+
+exports.dirname = function(path) {
+ var result = splitPath(path),
+ root = result[0],
+ dir = result[1];
+
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return '.';
+ }
+
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+
+ return root + dir;
+};
+
+
+exports.basename = function(path, ext) {
+ var f = splitPath(path)[2];
+ // TODO: make this comparison case-insensitive on windows?
+ if (ext && f.substr(-1 * ext.length) === ext) {
+ f = f.substr(0, f.length - ext.length);
+ }
+ return f;
+};
+
+
+exports.extname = function(path) {
+ return splitPath(path)[3];
+};
+
+function filter (xs, f) {
+ if (xs.filter) return xs.filter(f);
+ var res = [];
+ for (var i = 0; i < xs.length; i++) {
+ if (f(xs[i], i, xs)) res.push(xs[i]);
+ }
+ return res;
+}
+
+// String.prototype.substr - negative index don't work in IE8
+var substr = 'ab'.substr(-1) === 'b'
+ ? function (str, start, len) { return str.substr(start, len) }
+ : function (str, start, len) {
+ if (start < 0) start = str.length + start;
+ return str.substr(start, len);
+ }
+;
+
+},{"__browserify_process":1}],6:[function(require,module,exports){
+/*
+ Copyright (C) 2013 Ariya Hidayat
+ Copyright (C) 2013 Thaddee Tyl
+ Copyright (C) 2012 Ariya Hidayat
+ Copyright (C) 2012 Mathias Bynens
+ Copyright (C) 2012 Joost-Wim Boekesteijn
+ Copyright (C) 2012 Kris Kowal
+ Copyright (C) 2012 Yusuke Suzuki
+ Copyright (C) 2012 Arpad Borsos
+ Copyright (C) 2011 Ariya Hidayat
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*jslint bitwise:true plusplus:true */
+/*global esprima:true, define:true, exports:true, window: true,
+throwError: true, generateStatement: true, peek: true,
+parseAssignmentExpression: true, parseBlock: true,
+parseClassExpression: true, parseClassDeclaration: true, parseExpression: true,
+parseForStatement: true,
+parseFunctionDeclaration: true, parseFunctionExpression: true,
+parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseImportSpecifier: true,
+parseLeftHandSideExpression: true, parseParams: true, validateParam: true,
+parseSpreadOrAssignmentExpression: true,
+parseStatement: true, parseSourceElement: true, parseModuleBlock: true, parseConciseBody: true,
+advanceXJSChild: true, isXJSIdentifierStart: true, isXJSIdentifierPart: true,
+scanXJSStringLiteral: true, scanXJSIdentifier: true,
+parseXJSAttributeValue: true, parseXJSChild: true, parseXJSElement: true, parseXJSExpressionContainer: true, parseXJSEmptyExpression: true,
+parseTypeAnnotation: true, parseTypeAnnotatableIdentifier: true,
+parseYieldExpression: true
+*/
+
+(function (root, factory) {
+ 'use strict';
+
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
+ // Rhino, and plain browser loading.
+ if (typeof define === 'function' && define.amd) {
+ define(['exports'], factory);
+ } else if (typeof exports !== 'undefined') {
+ factory(exports);
+ } else {
+ factory((root.esprima = {}));
+ }
+}(this, function (exports) {
+ 'use strict';
+
+ var Token,
+ TokenName,
+ FnExprTokens,
+ Syntax,
+ PropertyKind,
+ Messages,
+ Regex,
+ SyntaxTreeDelegate,
+ XHTMLEntities,
+ ClassPropertyType,
+ source,
+ strict,
+ index,
+ lineNumber,
+ lineStart,
+ length,
+ delegate,
+ lookahead,
+ state,
+ extra;
+
+ Token = {
+ BooleanLiteral: 1,
+ EOF: 2,
+ Identifier: 3,
+ Keyword: 4,
+ NullLiteral: 5,
+ NumericLiteral: 6,
+ Punctuator: 7,
+ StringLiteral: 8,
+ RegularExpression: 9,
+ Template: 10,
+ XJSIdentifier: 11,
+ XJSText: 12
+ };
+
+ TokenName = {};
+ TokenName[Token.BooleanLiteral] = 'Boolean';
+ TokenName[Token.EOF] = '';
+ TokenName[Token.Identifier] = 'Identifier';
+ TokenName[Token.Keyword] = 'Keyword';
+ TokenName[Token.NullLiteral] = 'Null';
+ TokenName[Token.NumericLiteral] = 'Numeric';
+ TokenName[Token.Punctuator] = 'Punctuator';
+ TokenName[Token.StringLiteral] = 'String';
+ TokenName[Token.XJSIdentifier] = 'XJSIdentifier';
+ TokenName[Token.XJSText] = 'XJSText';
+ TokenName[Token.RegularExpression] = 'RegularExpression';
+
+ // A function following one of those tokens is an expression.
+ FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
+ 'return', 'case', 'delete', 'throw', 'void',
+ // assignment operators
+ '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
+ '&=', '|=', '^=', ',',
+ // binary/unary operators
+ '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
+ '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
+ '<=', '<', '>', '!=', '!=='];
+
+ Syntax = {
+ ArrayExpression: 'ArrayExpression',
+ ArrayPattern: 'ArrayPattern',
+ ArrowFunctionExpression: 'ArrowFunctionExpression',
+ AssignmentExpression: 'AssignmentExpression',
+ BinaryExpression: 'BinaryExpression',
+ BlockStatement: 'BlockStatement',
+ BreakStatement: 'BreakStatement',
+ CallExpression: 'CallExpression',
+ CatchClause: 'CatchClause',
+ ClassBody: 'ClassBody',
+ ClassDeclaration: 'ClassDeclaration',
+ ClassExpression: 'ClassExpression',
+ ClassHeritage: 'ClassHeritage',
+ ComprehensionBlock: 'ComprehensionBlock',
+ ComprehensionExpression: 'ComprehensionExpression',
+ ConditionalExpression: 'ConditionalExpression',
+ ContinueStatement: 'ContinueStatement',
+ DebuggerStatement: 'DebuggerStatement',
+ DoWhileStatement: 'DoWhileStatement',
+ EmptyStatement: 'EmptyStatement',
+ ExportDeclaration: 'ExportDeclaration',
+ ExportBatchSpecifier: 'ExportBatchSpecifier',
+ ExportSpecifier: 'ExportSpecifier',
+ ExpressionStatement: 'ExpressionStatement',
+ ForInStatement: 'ForInStatement',
+ ForOfStatement: 'ForOfStatement',
+ ForStatement: 'ForStatement',
+ FunctionDeclaration: 'FunctionDeclaration',
+ FunctionExpression: 'FunctionExpression',
+ Identifier: 'Identifier',
+ IfStatement: 'IfStatement',
+ ImportDeclaration: 'ImportDeclaration',
+ ImportSpecifier: 'ImportSpecifier',
+ LabeledStatement: 'LabeledStatement',
+ Literal: 'Literal',
+ LogicalExpression: 'LogicalExpression',
+ MemberExpression: 'MemberExpression',
+ MethodDefinition: 'MethodDefinition',
+ ModuleDeclaration: 'ModuleDeclaration',
+ NewExpression: 'NewExpression',
+ ObjectExpression: 'ObjectExpression',
+ ObjectPattern: 'ObjectPattern',
+ Program: 'Program',
+ Property: 'Property',
+ ReturnStatement: 'ReturnStatement',
+ SequenceExpression: 'SequenceExpression',
+ SpreadElement: 'SpreadElement',
+ SwitchCase: 'SwitchCase',
+ SwitchStatement: 'SwitchStatement',
+ TaggedTemplateExpression: 'TaggedTemplateExpression',
+ TemplateElement: 'TemplateElement',
+ TemplateLiteral: 'TemplateLiteral',
+ ThisExpression: 'ThisExpression',
+ ThrowStatement: 'ThrowStatement',
+ TryStatement: 'TryStatement',
+ TypeAnnotatedIdentifier: 'TypeAnnotatedIdentifier',
+ TypeAnnotation: 'TypeAnnotation',
+ UnaryExpression: 'UnaryExpression',
+ UpdateExpression: 'UpdateExpression',
+ VariableDeclaration: 'VariableDeclaration',
+ VariableDeclarator: 'VariableDeclarator',
+ WhileStatement: 'WhileStatement',
+ WithStatement: 'WithStatement',
+ XJSIdentifier: 'XJSIdentifier',
+ XJSEmptyExpression: 'XJSEmptyExpression',
+ XJSExpressionContainer: 'XJSExpressionContainer',
+ XJSElement: 'XJSElement',
+ XJSClosingElement: 'XJSClosingElement',
+ XJSOpeningElement: 'XJSOpeningElement',
+ XJSAttribute: 'XJSAttribute',
+ XJSText: 'XJSText',
+ YieldExpression: 'YieldExpression'
+ };
+
+ PropertyKind = {
+ Data: 1,
+ Get: 2,
+ Set: 4
+ };
+
+ ClassPropertyType = {
+ 'static': 'static',
+ prototype: 'prototype'
+ };
+
+ // Error messages should be identical to V8.
+ Messages = {
+ UnexpectedToken: 'Unexpected token %0',
+ UnexpectedNumber: 'Unexpected number',
+ UnexpectedString: 'Unexpected string',
+ UnexpectedIdentifier: 'Unexpected identifier',
+ UnexpectedReserved: 'Unexpected reserved word',
+ UnexpectedTemplate: 'Unexpected quasi %0',
+ UnexpectedEOS: 'Unexpected end of input',
+ NewlineAfterThrow: 'Illegal newline after throw',
+ InvalidRegExp: 'Invalid regular expression',
+ UnterminatedRegExp: 'Invalid regular expression: missing /',
+ InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
+ InvalidLHSInFormalsList: 'Invalid left-hand side in formals list',
+ InvalidLHSInForIn: 'Invalid left-hand side in for-in',
+ MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
+ NoCatchOrFinally: 'Missing catch or finally after try',
+ UnknownLabel: 'Undefined label \'%0\'',
+ Redeclaration: '%0 \'%1\' has already been declared',
+ IllegalContinue: 'Illegal continue statement',
+ IllegalBreak: 'Illegal break statement',
+ IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition',
+ IllegalReturn: 'Illegal return statement',
+ IllegalYield: 'Illegal yield expression',
+ IllegalSpread: 'Illegal spread element',
+ StrictModeWith: 'Strict mode code may not include a with statement',
+ StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
+ StrictVarName: 'Variable name may not be eval or arguments in strict mode',
+ StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
+ StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
+ ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list',
+ DefaultRestParameter: 'Rest parameter can not have a default value',
+ ElementAfterSpreadElement: 'Spread must be the final element of an element list',
+ ObjectPatternAsRestParameter: 'Invalid rest parameter',
+ ObjectPatternAsSpread: 'Invalid spread argument',
+ StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
+ StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
+ StrictDelete: 'Delete of an unqualified identifier in strict mode.',
+ StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
+ AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
+ AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
+ StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
+ StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictReservedWord: 'Use of future reserved word in strict mode',
+ NewlineAfterModule: 'Illegal newline after module',
+ NoFromAfterImport: 'Missing from after import',
+ InvalidModuleSpecifier: 'Invalid module specifier',
+ NestedModule: 'Module declaration can not be nested',
+ NoYieldInGenerator: 'Missing yield in generator',
+ NoUnintializedConst: 'Const must be initialized',
+ ComprehensionRequiresBlock: 'Comprehension must have at least one block',
+ ComprehensionError: 'Comprehension Error',
+ EachNotAllowed: 'Each is not supported',
+ InvalidXJSTagName: 'XJS tag name can not be empty',
+ InvalidXJSAttributeValue: 'XJS value should be either an expression or a quoted XJS text',
+ ExpectedXJSClosingTag: 'Expected corresponding XJS closing tag for %0'
+ };
+
+ // See also tools/generate-unicode-regex.py.
+ Regex = {
+ NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
+ NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
+ };
+
+ // Ensure the condition is true, otherwise throw an error.
+ // This is only to have a better contract semantic, i.e. another safety net
+ // to catch a logic error. The condition shall be fulfilled in normal case.
+ // Do NOT use this to enforce a certain condition on any user input.
+
+ function assert(condition, message) {
+ if (!condition) {
+ throw new Error('ASSERT: ' + message);
+ }
+ }
+
+ function isDecimalDigit(ch) {
+ return (ch >= 48 && ch <= 57); // 0..9
+ }
+
+ function isHexDigit(ch) {
+ return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+ }
+
+ function isOctalDigit(ch) {
+ return '01234567'.indexOf(ch) >= 0;
+ }
+
+
+ // 7.2 White Space
+
+ function isWhiteSpace(ch) {
+ return (ch === 32) || // space
+ (ch === 9) || // tab
+ (ch === 0xB) ||
+ (ch === 0xC) ||
+ (ch === 0xA0) ||
+ (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
+ }
+
+ // 7.3 Line Terminators
+
+ function isLineTerminator(ch) {
+ return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
+ }
+
+ // 7.6 Identifier Names and Identifiers
+
+ function isIdentifierStart(ch) {
+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
+ (ch >= 65 && ch <= 90) || // A..Z
+ (ch >= 97 && ch <= 122) || // a..z
+ (ch === 92) || // \ (backslash)
+ ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
+ }
+
+ function isIdentifierPart(ch) {
+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
+ (ch >= 65 && ch <= 90) || // A..Z
+ (ch >= 97 && ch <= 122) || // a..z
+ (ch >= 48 && ch <= 57) || // 0..9
+ (ch === 92) || // \ (backslash)
+ ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
+ }
+
+ // 7.6.1.2 Future Reserved Words
+
+ function isFutureReservedWord(id) {
+ switch (id) {
+ case 'class':
+ case 'enum':
+ case 'export':
+ case 'extends':
+ case 'import':
+ case 'super':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function isStrictModeReservedWord(id) {
+ switch (id) {
+ case 'implements':
+ case 'interface':
+ case 'package':
+ case 'private':
+ case 'protected':
+ case 'public':
+ case 'static':
+ case 'yield':
+ case 'let':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function isRestrictedWord(id) {
+ return id === 'eval' || id === 'arguments';
+ }
+
+ // 7.6.1.1 Keywords
+
+ function isKeyword(id) {
+ if (strict && isStrictModeReservedWord(id)) {
+ return true;
+ }
+
+ // 'const' is specialized as Keyword in V8.
+ // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
+ // Some others are from future reserved words.
+
+ switch (id.length) {
+ case 2:
+ return (id === 'if') || (id === 'in') || (id === 'do');
+ case 3:
+ return (id === 'var') || (id === 'for') || (id === 'new') ||
+ (id === 'try') || (id === 'let');
+ case 4:
+ return (id === 'this') || (id === 'else') || (id === 'case') ||
+ (id === 'void') || (id === 'with') || (id === 'enum');
+ case 5:
+ return (id === 'while') || (id === 'break') || (id === 'catch') ||
+ (id === 'throw') || (id === 'const') || (id === 'yield') ||
+ (id === 'class') || (id === 'super');
+ case 6:
+ return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
+ (id === 'switch') || (id === 'export') || (id === 'import');
+ case 7:
+ return (id === 'default') || (id === 'finally') || (id === 'extends');
+ case 8:
+ return (id === 'function') || (id === 'continue') || (id === 'debugger');
+ case 10:
+ return (id === 'instanceof');
+ default:
+ return false;
+ }
+ }
+
+ // 7.4 Comments
+
+ function skipComment() {
+ var ch, blockComment, lineComment;
+
+ blockComment = false;
+ lineComment = false;
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+
+ if (lineComment) {
+ ++index;
+ if (isLineTerminator(ch)) {
+ lineComment = false;
+ if (ch === 13 && source.charCodeAt(index) === 10) {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ }
+ } else if (blockComment) {
+ if (isLineTerminator(ch)) {
+ if (ch === 13 && source.charCodeAt(index + 1) === 10) {
+ ++index;
+ }
+ ++lineNumber;
+ ++index;
+ lineStart = index;
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else {
+ ch = source.charCodeAt(index++);
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ // Block comment ends with '*/' (char #42, char #47).
+ if (ch === 42) {
+ ch = source.charCodeAt(index);
+ if (ch === 47) {
+ ++index;
+ blockComment = false;
+ }
+ }
+ }
+ } else if (ch === 47) {
+ ch = source.charCodeAt(index + 1);
+ // Line comment starts with '//' (char #47, char #47).
+ if (ch === 47) {
+ index += 2;
+ lineComment = true;
+ } else if (ch === 42) {
+ // Block comment starts with '/*' (char #47, char #42).
+ index += 2;
+ blockComment = true;
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else {
+ break;
+ }
+ } else if (isWhiteSpace(ch)) {
+ ++index;
+ } else if (isLineTerminator(ch)) {
+ ++index;
+ if (ch === 13 && source.charCodeAt(index) === 10) {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ } else {
+ break;
+ }
+ }
+ }
+
+ function scanHexEscape(prefix) {
+ var i, len, ch, code = 0;
+
+ len = (prefix === 'u') ? 4 : 2;
+ for (i = 0; i < len; ++i) {
+ if (index < length && isHexDigit(source[index])) {
+ ch = source[index++];
+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+ } else {
+ return '';
+ }
+ }
+ return String.fromCharCode(code);
+ }
+
+ function scanUnicodeCodePointEscape() {
+ var ch, code, cu1, cu2;
+
+ ch = source[index];
+ code = 0;
+
+ // At least, one hex digit is required.
+ if (ch === '}') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ while (index < length) {
+ ch = source[index++];
+ if (!isHexDigit(ch)) {
+ break;
+ }
+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+ }
+
+ if (code > 0x10FFFF || ch !== '}') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ // UTF-16 Encoding
+ if (code <= 0xFFFF) {
+ return String.fromCharCode(code);
+ }
+ cu1 = ((code - 0x10000) >> 10) + 0xD800;
+ cu2 = ((code - 0x10000) & 1023) + 0xDC00;
+ return String.fromCharCode(cu1, cu2);
+ }
+
+ function getEscapedIdentifier() {
+ var ch, id;
+
+ ch = source.charCodeAt(index++);
+ id = String.fromCharCode(ch);
+
+ // '\u' (char #92, char #117) denotes an escaped character.
+ if (ch === 92) {
+ if (source.charCodeAt(index) !== 117) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ ++index;
+ ch = scanHexEscape('u');
+ if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ id = ch;
+ }
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (!isIdentifierPart(ch)) {
+ break;
+ }
+ ++index;
+ id += String.fromCharCode(ch);
+
+ // '\u' (char #92, char #117) denotes an escaped character.
+ if (ch === 92) {
+ id = id.substr(0, id.length - 1);
+ if (source.charCodeAt(index) !== 117) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ ++index;
+ ch = scanHexEscape('u');
+ if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ id += ch;
+ }
+ }
+
+ return id;
+ }
+
+ function getIdentifier() {
+ var start, ch;
+
+ start = index++;
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (ch === 92) {
+ // Blackslash (char #92) marks Unicode escape sequence.
+ index = start;
+ return getEscapedIdentifier();
+ }
+ if (isIdentifierPart(ch)) {
+ ++index;
+ } else {
+ break;
+ }
+ }
+
+ return source.slice(start, index);
+ }
+
+ function scanIdentifier() {
+ var start, id, type;
+
+ start = index;
+
+ // Backslash (char #92) starts an escaped character.
+ id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier();
+
+ // There is no keyword or literal with only one character.
+ // Thus, it must be an identifier.
+ if (id.length === 1) {
+ type = Token.Identifier;
+ } else if (isKeyword(id)) {
+ type = Token.Keyword;
+ } else if (id === 'null') {
+ type = Token.NullLiteral;
+ } else if (id === 'true' || id === 'false') {
+ type = Token.BooleanLiteral;
+ } else {
+ type = Token.Identifier;
+ }
+
+ return {
+ type: type,
+ value: id,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+
+ // 7.7 Punctuators
+
+ function scanPunctuator() {
+ var start = index,
+ code = source.charCodeAt(index),
+ code2,
+ ch1 = source[index],
+ ch2,
+ ch3,
+ ch4;
+
+ switch (code) {
+ // Check for most common single-character punctuators.
+ case 40: // ( open bracket
+ case 41: // ) close bracket
+ case 59: // ; semicolon
+ case 44: // , comma
+ case 123: // { open curly brace
+ case 125: // } close curly brace
+ case 91: // [
+ case 93: // ]
+ case 58: // :
+ case 63: // ?
+ case 126: // ~
+ ++index;
+ if (extra.tokenize) {
+ if (code === 40) {
+ extra.openParenToken = extra.tokens.length;
+ } else if (code === 123) {
+ extra.openCurlyToken = extra.tokens.length;
+ }
+ }
+ return {
+ type: Token.Punctuator,
+ value: String.fromCharCode(code),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+
+ default:
+ code2 = source.charCodeAt(index + 1);
+
+ // '=' (char #61) marks an assignment or comparison operator.
+ if (code2 === 61) {
+ switch (code) {
+ case 37: // %
+ case 38: // &
+ case 42: // *:
+ case 43: // +
+ case 45: // -
+ case 47: // /
+ case 60: // <
+ case 62: // >
+ case 94: // ^
+ case 124: // |
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: String.fromCharCode(code) + String.fromCharCode(code2),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+
+ case 33: // !
+ case 61: // =
+ index += 2;
+
+ // !== and ===
+ if (source.charCodeAt(index) === 61) {
+ ++index;
+ }
+ return {
+ type: Token.Punctuator,
+ value: source.slice(start, index),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ // Peek more characters.
+
+ ch2 = source[index + 1];
+ ch3 = source[index + 2];
+ ch4 = source[index + 3];
+
+ // 4-character punctuator: >>>=
+
+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+ if (ch4 === '=') {
+ index += 4;
+ return {
+ type: Token.Punctuator,
+ value: '>>>=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+ }
+
+ // 3-character punctuators: === !== >>> <<= >>=
+
+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '>>>',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '<<=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '>>=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '.' && ch2 === '.' && ch3 === '.') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '...',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ // Other 2-character punctuators: ++ -- << >> && ||
+
+ if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: ch1 + ch2,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '=' && ch2 === '>') {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: '=>',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
+ ++index;
+ return {
+ type: Token.Punctuator,
+ value: ch1,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '.') {
+ ++index;
+ return {
+ type: Token.Punctuator,
+ value: ch1,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ // 7.8.3 Numeric Literals
+
+ function scanHexLiteral(start) {
+ var number = '';
+
+ while (index < length) {
+ if (!isHexDigit(source[index])) {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (number.length === 0) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt('0x' + number, 16),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanOctalLiteral(prefix, start) {
+ var number, octal;
+
+ if (isOctalDigit(prefix)) {
+ octal = true;
+ number = '0' + source[index++];
+ } else {
+ octal = false;
+ ++index;
+ number = '';
+ }
+
+ while (index < length) {
+ if (!isOctalDigit(source[index])) {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (!octal && number.length === 0) {
+ // only 0o or 0O
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt(number, 8),
+ octal: octal,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanNumericLiteral() {
+ var number, start, ch, octal;
+
+ ch = source[index];
+ assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
+ 'Numeric literal must start with a decimal digit or a decimal point');
+
+ start = index;
+ number = '';
+ if (ch !== '.') {
+ number = source[index++];
+ ch = source[index];
+
+ // Hex number starts with '0x'.
+ // Octal number starts with '0'.
+ // Octal number in ES6 starts with '0o'.
+ // Binary number in ES6 starts with '0b'.
+ if (number === '0') {
+ if (ch === 'x' || ch === 'X') {
+ ++index;
+ return scanHexLiteral(start);
+ }
+ if (ch === 'b' || ch === 'B') {
+ ++index;
+ number = '';
+
+ while (index < length) {
+ ch = source[index];
+ if (ch !== '0' && ch !== '1') {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (number.length === 0) {
+ // only 0b or 0B
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (index < length) {
+ ch = source.charCodeAt(index);
+ if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt(number, 2),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+ if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) {
+ return scanOctalLiteral(ch, start);
+ }
+ // decimal number starts with '0' such as '09' is illegal.
+ if (ch && isDecimalDigit(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ ch = source[index];
+ }
+
+ if (ch === '.') {
+ number += source[index++];
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ ch = source[index];
+ }
+
+ if (ch === 'e' || ch === 'E') {
+ number += source[index++];
+
+ ch = source[index];
+ if (ch === '+' || ch === '-') {
+ number += source[index++];
+ }
+ if (isDecimalDigit(source.charCodeAt(index))) {
+ while (isDecimalDigit(source.charCodeAt(index))) {
+ number += source[index++];
+ }
+ } else {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+
+ if (isIdentifierStart(source.charCodeAt(index))) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseFloat(number),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ // 7.8.4 String Literals
+
+ function scanStringLiteral() {
+ var str = '', quote, start, ch, code, unescaped, restore, octal = false;
+
+ quote = source[index];
+ assert((quote === '\'' || quote === '"'),
+ 'String literal must starts with a quote');
+
+ start = index;
+ ++index;
+
+ while (index < length) {
+ ch = source[index++];
+
+ if (ch === quote) {
+ quote = '';
+ break;
+ } else if (ch === '\\') {
+ ch = source[index++];
+ if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
+ switch (ch) {
+ case 'n':
+ str += '\n';
+ break;
+ case 'r':
+ str += '\r';
+ break;
+ case 't':
+ str += '\t';
+ break;
+ case 'u':
+ case 'x':
+ if (source[index] === '{') {
+ ++index;
+ str += scanUnicodeCodePointEscape();
+ } else {
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ str += unescaped;
+ } else {
+ index = restore;
+ str += ch;
+ }
+ }
+ break;
+ case 'b':
+ str += '\b';
+ break;
+ case 'f':
+ str += '\f';
+ break;
+ case 'v':
+ str += '\x0B';
+ break;
+
+ default:
+ if (isOctalDigit(ch)) {
+ code = '01234567'.indexOf(ch);
+
+ // \0 is not octal escape sequence
+ if (code !== 0) {
+ octal = true;
+ }
+
+ if (index < length && isOctalDigit(source[index])) {
+ octal = true;
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ('0123'.indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source[index])) {
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+ }
+ }
+ str += String.fromCharCode(code);
+ } else {
+ str += ch;
+ }
+ break;
+ }
+ } else {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ }
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ break;
+ } else {
+ str += ch;
+ }
+ }
+
+ if (quote !== '') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.StringLiteral,
+ value: str,
+ octal: octal,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanTemplate() {
+ var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal;
+
+ terminated = false;
+ tail = false;
+ start = index;
+
+ ++index;
+
+ while (index < length) {
+ ch = source[index++];
+ if (ch === '`') {
+ tail = true;
+ terminated = true;
+ break;
+ } else if (ch === '$') {
+ if (source[index] === '{') {
+ ++index;
+ terminated = true;
+ break;
+ }
+ cooked += ch;
+ } else if (ch === '\\') {
+ ch = source[index++];
+ if (!isLineTerminator(ch.charCodeAt(0))) {
+ switch (ch) {
+ case 'n':
+ cooked += '\n';
+ break;
+ case 'r':
+ cooked += '\r';
+ break;
+ case 't':
+ cooked += '\t';
+ break;
+ case 'u':
+ case 'x':
+ if (source[index] === '{') {
+ ++index;
+ cooked += scanUnicodeCodePointEscape();
+ } else {
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ cooked += unescaped;
+ } else {
+ index = restore;
+ cooked += ch;
+ }
+ }
+ break;
+ case 'b':
+ cooked += '\b';
+ break;
+ case 'f':
+ cooked += '\f';
+ break;
+ case 'v':
+ cooked += '\v';
+ break;
+
+ default:
+ if (isOctalDigit(ch)) {
+ code = '01234567'.indexOf(ch);
+
+ // \0 is not octal escape sequence
+ if (code !== 0) {
+ octal = true;
+ }
+
+ if (index < length && isOctalDigit(source[index])) {
+ octal = true;
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ('0123'.indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source[index])) {
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+ }
+ }
+ cooked += String.fromCharCode(code);
+ } else {
+ cooked += ch;
+ }
+ break;
+ }
+ } else {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ }
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ cooked += '\n';
+ } else {
+ cooked += ch;
+ }
+ }
+
+ if (!terminated) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.Template,
+ value: {
+ cooked: cooked,
+ raw: source.slice(start + 1, index - ((tail) ? 1 : 2))
+ },
+ tail: tail,
+ octal: octal,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanTemplateElement(option) {
+ var startsWith, template;
+
+ lookahead = null;
+ skipComment();
+
+ startsWith = (option.head) ? '`' : '}';
+
+ if (source[index] !== startsWith) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ template = scanTemplate();
+
+ peek();
+
+ return template;
+ }
+
+ function scanRegExp() {
+ var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
+
+ lookahead = null;
+ skipComment();
+
+ start = index;
+ ch = source[index];
+ assert(ch === '/', 'Regular expression literal must start with a slash');
+ str = source[index++];
+
+ while (index < length) {
+ ch = source[index++];
+ str += ch;
+ if (classMarker) {
+ if (ch === ']') {
+ classMarker = false;
+ }
+ } else {
+ if (ch === '\\') {
+ ch = source[index++];
+ // ECMA-262 7.8.5
+ if (isLineTerminator(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+ str += ch;
+ } else if (ch === '/') {
+ terminated = true;
+ break;
+ } else if (ch === '[') {
+ classMarker = true;
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+ }
+ }
+
+ if (!terminated) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+
+ // Exclude leading and trailing slash.
+ pattern = str.substr(1, str.length - 2);
+
+ flags = '';
+ while (index < length) {
+ ch = source[index];
+ if (!isIdentifierPart(ch.charCodeAt(0))) {
+ break;
+ }
+
+ ++index;
+ if (ch === '\\' && index < length) {
+ ch = source[index];
+ if (ch === 'u') {
+ ++index;
+ restore = index;
+ ch = scanHexEscape('u');
+ if (ch) {
+ flags += ch;
+ for (str += '\\u'; restore < index; ++restore) {
+ str += source[restore];
+ }
+ } else {
+ index = restore;
+ flags += 'u';
+ str += '\\u';
+ }
+ } else {
+ str += '\\';
+ }
+ } else {
+ flags += ch;
+ str += ch;
+ }
+ }
+
+ try {
+ value = new RegExp(pattern, flags);
+ } catch (e) {
+ throwError({}, Messages.InvalidRegExp);
+ }
+
+ peek();
+
+
+ if (extra.tokenize) {
+ return {
+ type: Token.RegularExpression,
+ value: value,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+ return {
+ literal: str,
+ value: value,
+ range: [start, index]
+ };
+ }
+
+ function isIdentifierName(token) {
+ return token.type === Token.Identifier ||
+ token.type === Token.Keyword ||
+ token.type === Token.BooleanLiteral ||
+ token.type === Token.NullLiteral;
+ }
+
+ function advanceSlash() {
+ var prevToken,
+ checkToken;
+ // Using the following algorithm:
+ // https://github.com/mozilla/sweet.js/wiki/design
+ prevToken = extra.tokens[extra.tokens.length - 1];
+ if (!prevToken) {
+ // Nothing before that: it cannot be a division.
+ return scanRegExp();
+ }
+ if (prevToken.type === 'Punctuator') {
+ if (prevToken.value === ')') {
+ checkToken = extra.tokens[extra.openParenToken - 1];
+ if (checkToken &&
+ checkToken.type === 'Keyword' &&
+ (checkToken.value === 'if' ||
+ checkToken.value === 'while' ||
+ checkToken.value === 'for' ||
+ checkToken.value === 'with')) {
+ return scanRegExp();
+ }
+ return scanPunctuator();
+ }
+ if (prevToken.value === '}') {
+ // Dividing a function by anything makes little sense,
+ // but we have to check for that.
+ if (extra.tokens[extra.openCurlyToken - 3] &&
+ extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
+ // Anonymous function.
+ checkToken = extra.tokens[extra.openCurlyToken - 4];
+ if (!checkToken) {
+ return scanPunctuator();
+ }
+ } else if (extra.tokens[extra.openCurlyToken - 4] &&
+ extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
+ // Named function.
+ checkToken = extra.tokens[extra.openCurlyToken - 5];
+ if (!checkToken) {
+ return scanRegExp();
+ }
+ } else {
+ return scanPunctuator();
+ }
+ // checkToken determines whether the function is
+ // a declaration or an expression.
+ if (FnExprTokens.indexOf(checkToken.value) >= 0) {
+ // It is an expression.
+ return scanPunctuator();
+ }
+ // It is a declaration.
+ return scanRegExp();
+ }
+ return scanRegExp();
+ }
+ if (prevToken.type === 'Keyword') {
+ return scanRegExp();
+ }
+ return scanPunctuator();
+ }
+
+ function advance() {
+ var ch;
+
+ if (!state.inXJSChild) {
+ skipComment();
+ }
+
+ if (index >= length) {
+ return {
+ type: Token.EOF,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [index, index]
+ };
+ }
+
+ if (state.inXJSChild) {
+ return advanceXJSChild();
+ }
+
+ ch = source.charCodeAt(index);
+
+ // Very common: ( and ) and ;
+ if (ch === 40 || ch === 41 || ch === 58) {
+ return scanPunctuator();
+ }
+
+ // String literal starts with single quote (#39) or double quote (#34).
+ if (ch === 39 || ch === 34) {
+ if (state.inXJSTag) {
+ return scanXJSStringLiteral();
+ }
+ return scanStringLiteral();
+ }
+
+ if (state.inXJSTag && isXJSIdentifierStart(ch)) {
+ return scanXJSIdentifier();
+ }
+
+ if (ch === 96) {
+ return scanTemplate();
+ }
+ if (isIdentifierStart(ch)) {
+ return scanIdentifier();
+ }
+
+ // Dot (.) char #46 can also start a floating-point number, hence the need
+ // to check the next character.
+ if (ch === 46) {
+ if (isDecimalDigit(source.charCodeAt(index + 1))) {
+ return scanNumericLiteral();
+ }
+ return scanPunctuator();
+ }
+
+ if (isDecimalDigit(ch)) {
+ return scanNumericLiteral();
+ }
+
+ // Slash (/) char #47 can also start a regex.
+ if (extra.tokenize && ch === 47) {
+ return advanceSlash();
+ }
+
+ return scanPunctuator();
+ }
+
+ function lex() {
+ var token;
+
+ token = lookahead;
+ index = token.range[1];
+ lineNumber = token.lineNumber;
+ lineStart = token.lineStart;
+
+ lookahead = advance();
+
+ index = token.range[1];
+ lineNumber = token.lineNumber;
+ lineStart = token.lineStart;
+
+ return token;
+ }
+
+ function peek() {
+ var pos, line, start;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+ lookahead = advance();
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+ }
+
+ function lookahead2() {
+ var adv, pos, line, start, result;
+
+ // If we are collecting the tokens, don't grab the next one yet.
+ adv = (typeof extra.advance === 'function') ? extra.advance : advance;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+
+ // Scan for the next immediate token.
+ if (lookahead === null) {
+ lookahead = adv();
+ }
+ index = lookahead.range[1];
+ lineNumber = lookahead.lineNumber;
+ lineStart = lookahead.lineStart;
+
+ // Grab the token right after.
+ result = adv();
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+
+ return result;
+ }
+
+ SyntaxTreeDelegate = {
+
+ name: 'SyntaxTree',
+
+ postProcess: function (node) {
+ return node;
+ },
+
+ createArrayExpression: function (elements) {
+ return {
+ type: Syntax.ArrayExpression,
+ elements: elements
+ };
+ },
+
+ createAssignmentExpression: function (operator, left, right) {
+ return {
+ type: Syntax.AssignmentExpression,
+ operator: operator,
+ left: left,
+ right: right
+ };
+ },
+
+ createBinaryExpression: function (operator, left, right) {
+ var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
+ Syntax.BinaryExpression;
+ return {
+ type: type,
+ operator: operator,
+ left: left,
+ right: right
+ };
+ },
+
+ createBlockStatement: function (body) {
+ return {
+ type: Syntax.BlockStatement,
+ body: body
+ };
+ },
+
+ createBreakStatement: function (label) {
+ return {
+ type: Syntax.BreakStatement,
+ label: label
+ };
+ },
+
+ createCallExpression: function (callee, args) {
+ return {
+ type: Syntax.CallExpression,
+ callee: callee,
+ 'arguments': args
+ };
+ },
+
+ createCatchClause: function (param, body) {
+ return {
+ type: Syntax.CatchClause,
+ param: param,
+ body: body
+ };
+ },
+
+ createConditionalExpression: function (test, consequent, alternate) {
+ return {
+ type: Syntax.ConditionalExpression,
+ test: test,
+ consequent: consequent,
+ alternate: alternate
+ };
+ },
+
+ createContinueStatement: function (label) {
+ return {
+ type: Syntax.ContinueStatement,
+ label: label
+ };
+ },
+
+ createDebuggerStatement: function () {
+ return {
+ type: Syntax.DebuggerStatement
+ };
+ },
+
+ createDoWhileStatement: function (body, test) {
+ return {
+ type: Syntax.DoWhileStatement,
+ body: body,
+ test: test
+ };
+ },
+
+ createEmptyStatement: function () {
+ return {
+ type: Syntax.EmptyStatement
+ };
+ },
+
+ createExpressionStatement: function (expression) {
+ return {
+ type: Syntax.ExpressionStatement,
+ expression: expression
+ };
+ },
+
+ createForStatement: function (init, test, update, body) {
+ return {
+ type: Syntax.ForStatement,
+ init: init,
+ test: test,
+ update: update,
+ body: body
+ };
+ },
+
+ createForInStatement: function (left, right, body) {
+ return {
+ type: Syntax.ForInStatement,
+ left: left,
+ right: right,
+ body: body,
+ each: false
+ };
+ },
+
+ createForOfStatement: function (left, right, body) {
+ return {
+ type: Syntax.ForOfStatement,
+ left: left,
+ right: right,
+ body: body
+ };
+ },
+
+ createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression,
+ returnType) {
+ return {
+ type: Syntax.FunctionDeclaration,
+ id: id,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: rest,
+ generator: generator,
+ expression: expression,
+ returnType: returnType
+ };
+ },
+
+ createFunctionExpression: function (id, params, defaults, body, rest, generator, expression,
+ returnType) {
+ return {
+ type: Syntax.FunctionExpression,
+ id: id,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: rest,
+ generator: generator,
+ expression: expression,
+ returnType: returnType
+ };
+ },
+
+ createIdentifier: function (name) {
+ return {
+ type: Syntax.Identifier,
+ name: name,
+ // Only here to initialize the shape of the object to ensure
+ // that the 'typeAnnotation' key is ordered before others that
+ // are added later (like 'loc' and 'range'). This just helps
+ // keep the shape of Identifier nodes consistent with everything
+ // else.
+ typeAnnotation: undefined
+ };
+ },
+
+ createTypeAnnotation: function (typeIdentifier, paramTypes, returnType, nullable) {
+ return {
+ type: Syntax.TypeAnnotation,
+ id: typeIdentifier,
+ paramTypes: paramTypes,
+ returnType: returnType,
+ nullable: nullable
+ };
+ },
+
+ createTypeAnnotatedIdentifier: function (identifier, annotation) {
+ return {
+ type: Syntax.TypeAnnotatedIdentifier,
+ id: identifier,
+ annotation: annotation
+ };
+ },
+
+ createXJSAttribute: function (name, value) {
+ return {
+ type: Syntax.XJSAttribute,
+ name: name,
+ value: value
+ };
+ },
+
+ createXJSIdentifier: function (name, namespace) {
+ return {
+ type: Syntax.XJSIdentifier,
+ name: name,
+ namespace: namespace
+ };
+ },
+
+ createXJSElement: function (openingElement, closingElement, children) {
+ return {
+ type: Syntax.XJSElement,
+ openingElement: openingElement,
+ closingElement: closingElement,
+ children: children
+ };
+ },
+
+ createXJSEmptyExpression: function () {
+ return {
+ type: Syntax.XJSEmptyExpression
+ };
+ },
+
+ createXJSExpressionContainer: function (expression) {
+ return {
+ type: Syntax.XJSExpressionContainer,
+ expression: expression
+ };
+ },
+
+ createXJSOpeningElement: function (name, attributes, selfClosing) {
+ return {
+ type: Syntax.XJSOpeningElement,
+ name: name,
+ selfClosing: selfClosing,
+ attributes: attributes
+ };
+ },
+
+ createXJSClosingElement: function (name) {
+ return {
+ type: Syntax.XJSClosingElement,
+ name: name
+ };
+ },
+
+ createIfStatement: function (test, consequent, alternate) {
+ return {
+ type: Syntax.IfStatement,
+ test: test,
+ consequent: consequent,
+ alternate: alternate
+ };
+ },
+
+ createLabeledStatement: function (label, body) {
+ return {
+ type: Syntax.LabeledStatement,
+ label: label,
+ body: body
+ };
+ },
+
+ createLiteral: function (token) {
+ return {
+ type: Syntax.Literal,
+ value: token.value,
+ raw: source.slice(token.range[0], token.range[1])
+ };
+ },
+
+ createMemberExpression: function (accessor, object, property) {
+ return {
+ type: Syntax.MemberExpression,
+ computed: accessor === '[',
+ object: object,
+ property: property
+ };
+ },
+
+ createNewExpression: function (callee, args) {
+ return {
+ type: Syntax.NewExpression,
+ callee: callee,
+ 'arguments': args
+ };
+ },
+
+ createObjectExpression: function (properties) {
+ return {
+ type: Syntax.ObjectExpression,
+ properties: properties
+ };
+ },
+
+ createPostfixExpression: function (operator, argument) {
+ return {
+ type: Syntax.UpdateExpression,
+ operator: operator,
+ argument: argument,
+ prefix: false
+ };
+ },
+
+ createProgram: function (body) {
+ return {
+ type: Syntax.Program,
+ body: body
+ };
+ },
+
+ createProperty: function (kind, key, value, method, shorthand) {
+ return {
+ type: Syntax.Property,
+ key: key,
+ value: value,
+ kind: kind,
+ method: method,
+ shorthand: shorthand
+ };
+ },
+
+ createReturnStatement: function (argument) {
+ return {
+ type: Syntax.ReturnStatement,
+ argument: argument
+ };
+ },
+
+ createSequenceExpression: function (expressions) {
+ return {
+ type: Syntax.SequenceExpression,
+ expressions: expressions
+ };
+ },
+
+ createSwitchCase: function (test, consequent) {
+ return {
+ type: Syntax.SwitchCase,
+ test: test,
+ consequent: consequent
+ };
+ },
+
+ createSwitchStatement: function (discriminant, cases) {
+ return {
+ type: Syntax.SwitchStatement,
+ discriminant: discriminant,
+ cases: cases
+ };
+ },
+
+ createThisExpression: function () {
+ return {
+ type: Syntax.ThisExpression
+ };
+ },
+
+ createThrowStatement: function (argument) {
+ return {
+ type: Syntax.ThrowStatement,
+ argument: argument
+ };
+ },
+
+ createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
+ return {
+ type: Syntax.TryStatement,
+ block: block,
+ guardedHandlers: guardedHandlers,
+ handlers: handlers,
+ finalizer: finalizer
+ };
+ },
+
+ createUnaryExpression: function (operator, argument) {
+ if (operator === '++' || operator === '--') {
+ return {
+ type: Syntax.UpdateExpression,
+ operator: operator,
+ argument: argument,
+ prefix: true
+ };
+ }
+ return {
+ type: Syntax.UnaryExpression,
+ operator: operator,
+ argument: argument
+ };
+ },
+
+ createVariableDeclaration: function (declarations, kind) {
+ return {
+ type: Syntax.VariableDeclaration,
+ declarations: declarations,
+ kind: kind
+ };
+ },
+
+ createVariableDeclarator: function (id, init) {
+ return {
+ type: Syntax.VariableDeclarator,
+ id: id,
+ init: init
+ };
+ },
+
+ createWhileStatement: function (test, body) {
+ return {
+ type: Syntax.WhileStatement,
+ test: test,
+ body: body
+ };
+ },
+
+ createWithStatement: function (object, body) {
+ return {
+ type: Syntax.WithStatement,
+ object: object,
+ body: body
+ };
+ },
+
+ createTemplateElement: function (value, tail) {
+ return {
+ type: Syntax.TemplateElement,
+ value: value,
+ tail: tail
+ };
+ },
+
+ createTemplateLiteral: function (quasis, expressions) {
+ return {
+ type: Syntax.TemplateLiteral,
+ quasis: quasis,
+ expressions: expressions
+ };
+ },
+
+ createSpreadElement: function (argument) {
+ return {
+ type: Syntax.SpreadElement,
+ argument: argument
+ };
+ },
+
+ createTaggedTemplateExpression: function (tag, quasi) {
+ return {
+ type: Syntax.TaggedTemplateExpression,
+ tag: tag,
+ quasi: quasi
+ };
+ },
+
+ createArrowFunctionExpression: function (params, defaults, body, rest, expression) {
+ return {
+ type: Syntax.ArrowFunctionExpression,
+ id: null,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: rest,
+ generator: false,
+ expression: expression
+ };
+ },
+
+ createMethodDefinition: function (propertyType, kind, key, value) {
+ return {
+ type: Syntax.MethodDefinition,
+ key: key,
+ value: value,
+ kind: kind,
+ 'static': propertyType === ClassPropertyType["static"]
+ };
+ },
+
+ createClassBody: function (body) {
+ return {
+ type: Syntax.ClassBody,
+ body: body
+ };
+ },
+
+ createClassExpression: function (id, superClass, body) {
+ return {
+ type: Syntax.ClassExpression,
+ id: id,
+ superClass: superClass,
+ body: body
+ };
+ },
+
+ createClassDeclaration: function (id, superClass, body) {
+ return {
+ type: Syntax.ClassDeclaration,
+ id: id,
+ superClass: superClass,
+ body: body
+ };
+ },
+
+ createExportSpecifier: function (id, name) {
+ return {
+ type: Syntax.ExportSpecifier,
+ id: id,
+ name: name
+ };
+ },
+
+ createExportBatchSpecifier: function () {
+ return {
+ type: Syntax.ExportBatchSpecifier
+ };
+ },
+
+ createExportDeclaration: function (declaration, specifiers, source) {
+ return {
+ type: Syntax.ExportDeclaration,
+ declaration: declaration,
+ specifiers: specifiers,
+ source: source
+ };
+ },
+
+ createImportSpecifier: function (id, name) {
+ return {
+ type: Syntax.ImportSpecifier,
+ id: id,
+ name: name
+ };
+ },
+
+ createImportDeclaration: function (specifiers, kind, source) {
+ return {
+ type: Syntax.ImportDeclaration,
+ specifiers: specifiers,
+ kind: kind,
+ source: source
+ };
+ },
+
+ createYieldExpression: function (argument, delegate) {
+ return {
+ type: Syntax.YieldExpression,
+ argument: argument,
+ delegate: delegate
+ };
+ },
+
+ createModuleDeclaration: function (id, source, body) {
+ return {
+ type: Syntax.ModuleDeclaration,
+ id: id,
+ source: source,
+ body: body
+ };
+ }
+
+
+ };
+
+ // Return true if there is a line terminator before the next token.
+
+ function peekLineTerminator() {
+ var pos, line, start, found;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+ skipComment();
+ found = lineNumber !== line;
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+
+ return found;
+ }
+
+ // Throw an exception
+
+ function throwError(token, messageFormat) {
+ var error,
+ args = Array.prototype.slice.call(arguments, 2),
+ msg = messageFormat.replace(
+ /%(\d)/g,
+ function (whole, index) {
+ assert(index < args.length, 'Message reference must be in range');
+ return args[index];
+ }
+ );
+
+ if (typeof token.lineNumber === 'number') {
+ error = new Error('Line ' + token.lineNumber + ': ' + msg);
+ error.index = token.range[0];
+ error.lineNumber = token.lineNumber;
+ error.column = token.range[0] - lineStart + 1;
+ } else {
+ error = new Error('Line ' + lineNumber + ': ' + msg);
+ error.index = index;
+ error.lineNumber = lineNumber;
+ error.column = index - lineStart + 1;
+ }
+
+ error.description = msg;
+ throw error;
+ }
+
+ function throwErrorTolerant() {
+ try {
+ throwError.apply(null, arguments);
+ } catch (e) {
+ if (extra.errors) {
+ extra.errors.push(e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+
+ // Throw an exception because of the token.
+
+ function throwUnexpected(token) {
+ if (token.type === Token.EOF) {
+ throwError(token, Messages.UnexpectedEOS);
+ }
+
+ if (token.type === Token.NumericLiteral) {
+ throwError(token, Messages.UnexpectedNumber);
+ }
+
+ if (token.type === Token.StringLiteral || token.type === Token.XJSText) {
+ throwError(token, Messages.UnexpectedString);
+ }
+
+ if (token.type === Token.Identifier) {
+ throwError(token, Messages.UnexpectedIdentifier);
+ }
+
+ if (token.type === Token.Keyword) {
+ if (isFutureReservedWord(token.value)) {
+ throwError(token, Messages.UnexpectedReserved);
+ } else if (strict && isStrictModeReservedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictReservedWord);
+ return;
+ }
+ throwError(token, Messages.UnexpectedToken, token.value);
+ }
+
+ if (token.type === Token.Template) {
+ throwError(token, Messages.UnexpectedTemplate, token.value.raw);
+ }
+
+ // BooleanLiteral, NullLiteral, or Punctuator.
+ throwError(token, Messages.UnexpectedToken, token.value);
+ }
+
+ // Expect the next token to match the specified punctuator.
+ // If not, an exception will be thrown.
+
+ function expect(value) {
+ var token = lex();
+ if (token.type !== Token.Punctuator || token.value !== value) {
+ throwUnexpected(token);
+ }
+ }
+
+ // Expect the next token to match the specified keyword.
+ // If not, an exception will be thrown.
+
+ function expectKeyword(keyword) {
+ var token = lex();
+ if (token.type !== Token.Keyword || token.value !== keyword) {
+ throwUnexpected(token);
+ }
+ }
+
+ // Return true if the next token matches the specified punctuator.
+
+ function match(value) {
+ return lookahead.type === Token.Punctuator && lookahead.value === value;
+ }
+
+ // Return true if the next token matches the specified keyword
+
+ function matchKeyword(keyword) {
+ return lookahead.type === Token.Keyword && lookahead.value === keyword;
+ }
+
+
+ // Return true if the next token matches the specified contextual keyword
+
+ function matchContextualKeyword(keyword) {
+ return lookahead.type === Token.Identifier && lookahead.value === keyword;
+ }
+
+ // Return true if the next token is an assignment operator
+
+ function matchAssign() {
+ var op;
+
+ if (lookahead.type !== Token.Punctuator) {
+ return false;
+ }
+ op = lookahead.value;
+ return op === '=' ||
+ op === '*=' ||
+ op === '/=' ||
+ op === '%=' ||
+ op === '+=' ||
+ op === '-=' ||
+ op === '<<=' ||
+ op === '>>=' ||
+ op === '>>>=' ||
+ op === '&=' ||
+ op === '^=' ||
+ op === '|=';
+ }
+
+ function consumeSemicolon() {
+ var line;
+
+ // Catch the very common case first: immediately a semicolon (char #59).
+ if (source.charCodeAt(index) === 59) {
+ lex();
+ return;
+ }
+
+ line = lineNumber;
+ skipComment();
+ if (lineNumber !== line) {
+ return;
+ }
+
+ if (match(';')) {
+ lex();
+ return;
+ }
+
+ if (lookahead.type !== Token.EOF && !match('}')) {
+ throwUnexpected(lookahead);
+ }
+ }
+
+ // Return true if provided expression is LeftHandSideExpression
+
+ function isLeftHandSide(expr) {
+ return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
+ }
+
+ function isAssignableLeftHandSide(expr) {
+ return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern;
+ }
+
+ // 11.1.4 Array Initialiser
+
+ function parseArrayInitialiser() {
+ var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true, body;
+
+ expect('[');
+ while (!match(']')) {
+ if (lookahead.value === 'for' &&
+ lookahead.type === Token.Keyword) {
+ if (!possiblecomprehension) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ matchKeyword('for');
+ tmp = parseForStatement({ignoreBody: true});
+ tmp.of = tmp.type === Syntax.ForOfStatement;
+ tmp.type = Syntax.ComprehensionBlock;
+ if (tmp.left.kind) { // can't be let or const
+ throwError({}, Messages.ComprehensionError);
+ }
+ blocks.push(tmp);
+ } else if (lookahead.value === 'if' &&
+ lookahead.type === Token.Keyword) {
+ if (!possiblecomprehension) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ expectKeyword('if');
+ expect('(');
+ filter = parseExpression();
+ expect(')');
+ } else if (lookahead.value === ',' &&
+ lookahead.type === Token.Punctuator) {
+ possiblecomprehension = false; // no longer allowed.
+ lex();
+ elements.push(null);
+ } else {
+ tmp = parseSpreadOrAssignmentExpression();
+ elements.push(tmp);
+ if (tmp && tmp.type === Syntax.SpreadElement) {
+ if (!match(']')) {
+ throwError({}, Messages.ElementAfterSpreadElement);
+ }
+ } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) {
+ expect(','); // this lexes.
+ possiblecomprehension = false;
+ }
+ }
+ }
+
+ expect(']');
+
+ if (filter && !blocks.length) {
+ throwError({}, Messages.ComprehensionRequiresBlock);
+ }
+
+ if (blocks.length) {
+ if (elements.length !== 1) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ return {
+ type: Syntax.ComprehensionExpression,
+ filter: filter,
+ blocks: blocks,
+ body: elements[0]
+ };
+ }
+ return delegate.createArrayExpression(elements);
+ }
+
+ // 11.1.5 Object Initialiser
+
+ function parsePropertyFunction(options) {
+ var previousStrict, previousYieldAllowed, params, defaults, body;
+
+ previousStrict = strict;
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = options.generator;
+ params = options.params || [];
+ defaults = options.defaults || [];
+
+ body = parseConciseBody();
+ if (options.name && strict && isRestrictedWord(params[0].name)) {
+ throwErrorTolerant(options.name, Messages.StrictParamName);
+ }
+ if (state.yieldAllowed && !state.yieldFound) {
+ throwErrorTolerant({}, Messages.NoYieldInGenerator);
+ }
+ strict = previousStrict;
+ state.yieldAllowed = previousYieldAllowed;
+
+ return delegate.createFunctionExpression(null, params, defaults, body, options.rest || null, options.generator, body.type !== Syntax.BlockStatement,
+ options.returnTypeAnnotation);
+ }
+
+
+ function parsePropertyMethodFunction(options) {
+ var previousStrict, tmp, method;
+
+ previousStrict = strict;
+ strict = true;
+
+ tmp = parseParams();
+
+ if (tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, tmp.message);
+ }
+
+
+ method = parsePropertyFunction({
+ params: tmp.params,
+ defaults: tmp.defaults,
+ rest: tmp.rest,
+ generator: options.generator,
+ returnTypeAnnotation: tmp.returnTypeAnnotation
+ });
+
+ strict = previousStrict;
+
+ return method;
+ }
+
+
+ function parseObjectPropertyKey() {
+ var token = lex();
+
+ // Note: This function is called only from parseObjectProperty(), where
+ // EOF and Punctuator tokens are already filtered out.
+
+ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
+ if (strict && token.octal) {
+ throwErrorTolerant(token, Messages.StrictOctalLiteral);
+ }
+ return delegate.createLiteral(token);
+ }
+
+ return delegate.createIdentifier(token.value);
+ }
+
+ function parseObjectProperty() {
+ var token, key, id, value, param;
+
+ token = lookahead;
+
+ if (token.type === Token.Identifier) {
+
+ id = parseObjectPropertyKey();
+
+ // Property Assignment: Getter and Setter.
+
+ if (token.value === 'get' && !(match(':') || match('('))) {
+ key = parseObjectPropertyKey();
+ expect('(');
+ expect(')');
+ return delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false);
+ }
+ if (token.value === 'set' && !(match(':') || match('('))) {
+ key = parseObjectPropertyKey();
+ expect('(');
+ token = lookahead;
+ param = [ parseTypeAnnotatableIdentifier() ];
+ expect(')');
+ return delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false);
+ }
+ if (match(':')) {
+ lex();
+ return delegate.createProperty('init', id, parseAssignmentExpression(), false, false);
+ }
+ if (match('(')) {
+ return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false);
+ }
+ return delegate.createProperty('init', id, id, false, true);
+ }
+ if (token.type === Token.EOF || token.type === Token.Punctuator) {
+ if (!match('*')) {
+ throwUnexpected(token);
+ }
+ lex();
+
+ id = parseObjectPropertyKey();
+
+ if (!match('(')) {
+ throwUnexpected(lex());
+ }
+
+ return delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false);
+ }
+ key = parseObjectPropertyKey();
+ if (match(':')) {
+ lex();
+ return delegate.createProperty('init', key, parseAssignmentExpression(), false, false);
+ }
+ if (match('(')) {
+ return delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false);
+ }
+ throwUnexpected(lex());
+ }
+
+ function parseObjectInitialiser() {
+ var properties = [], property, name, key, kind, map = {}, toString = String;
+
+ expect('{');
+
+ while (!match('}')) {
+ property = parseObjectProperty();
+
+ if (property.key.type === Syntax.Identifier) {
+ name = property.key.name;
+ } else {
+ name = toString(property.key.value);
+ }
+ kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
+
+ key = '$' + name;
+ if (Object.prototype.hasOwnProperty.call(map, key)) {
+ if (map[key] === PropertyKind.Data) {
+ if (strict && kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.StrictDuplicateProperty);
+ } else if (kind !== PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ }
+ } else {
+ if (kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ } else if (map[key] & kind) {
+ throwErrorTolerant({}, Messages.AccessorGetSet);
+ }
+ }
+ map[key] |= kind;
+ } else {
+ map[key] = kind;
+ }
+
+ properties.push(property);
+
+ if (!match('}')) {
+ expect(',');
+ }
+ }
+
+ expect('}');
+
+ return delegate.createObjectExpression(properties);
+ }
+
+ function parseTemplateElement(option) {
+ var token = scanTemplateElement(option);
+ if (strict && token.octal) {
+ throwError(token, Messages.StrictOctalLiteral);
+ }
+ return delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
+ }
+
+ function parseTemplateLiteral() {
+ var quasi, quasis, expressions;
+
+ quasi = parseTemplateElement({ head: true });
+ quasis = [ quasi ];
+ expressions = [];
+
+ while (!quasi.tail) {
+ expressions.push(parseExpression());
+ quasi = parseTemplateElement({ head: false });
+ quasis.push(quasi);
+ }
+
+ return delegate.createTemplateLiteral(quasis, expressions);
+ }
+
+ // 11.1.6 The Grouping Operator
+
+ function parseGroupExpression() {
+ var expr;
+
+ expect('(');
+
+ ++state.parenthesizedCount;
+
+ expr = parseExpression();
+
+ expect(')');
+
+ return expr;
+ }
+
+
+ // 11.1 Primary Expressions
+
+ function parsePrimaryExpression() {
+ var type, token;
+
+ token = lookahead;
+ type = lookahead.type;
+
+ if (type === Token.Identifier) {
+ lex();
+ return delegate.createIdentifier(token.value);
+ }
+
+ if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+ if (strict && lookahead.octal) {
+ throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
+ }
+ return delegate.createLiteral(lex());
+ }
+
+ if (type === Token.Keyword) {
+ if (matchKeyword('this')) {
+ lex();
+ return delegate.createThisExpression();
+ }
+
+ if (matchKeyword('function')) {
+ return parseFunctionExpression();
+ }
+
+ if (matchKeyword('class')) {
+ return parseClassExpression();
+ }
+
+ if (matchKeyword('super')) {
+ lex();
+ return delegate.createIdentifier('super');
+ }
+ }
+
+ if (type === Token.BooleanLiteral) {
+ token = lex();
+ token.value = (token.value === 'true');
+ return delegate.createLiteral(token);
+ }
+
+ if (type === Token.NullLiteral) {
+ token = lex();
+ token.value = null;
+ return delegate.createLiteral(token);
+ }
+
+ if (match('[')) {
+ return parseArrayInitialiser();
+ }
+
+ if (match('{')) {
+ return parseObjectInitialiser();
+ }
+
+ if (match('(')) {
+ return parseGroupExpression();
+ }
+
+ if (match('/') || match('/=')) {
+ return delegate.createLiteral(scanRegExp());
+ }
+
+ if (type === Token.Template) {
+ return parseTemplateLiteral();
+ }
+
+ if (match('<')) {
+ return parseXJSElement();
+ }
+
+ return throwUnexpected(lex());
+ }
+
+ // 11.2 Left-Hand-Side Expressions
+
+ function parseArguments() {
+ var args = [], arg;
+
+ expect('(');
+
+ if (!match(')')) {
+ while (index < length) {
+ arg = parseSpreadOrAssignmentExpression();
+ args.push(arg);
+
+ if (match(')')) {
+ break;
+ } else if (arg.type === Syntax.SpreadElement) {
+ throwError({}, Messages.ElementAfterSpreadElement);
+ }
+
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ return args;
+ }
+
+ function parseSpreadOrAssignmentExpression() {
+ if (match('...')) {
+ lex();
+ return delegate.createSpreadElement(parseAssignmentExpression());
+ }
+ return parseAssignmentExpression();
+ }
+
+ function parseNonComputedProperty() {
+ var token = lex();
+
+ if (!isIdentifierName(token)) {
+ throwUnexpected(token);
+ }
+
+ return delegate.createIdentifier(token.value);
+ }
+
+ function parseNonComputedMember() {
+ expect('.');
+
+ return parseNonComputedProperty();
+ }
+
+ function parseComputedMember() {
+ var expr;
+
+ expect('[');
+
+ expr = parseExpression();
+
+ expect(']');
+
+ return expr;
+ }
+
+ function parseNewExpression() {
+ var callee, args;
+
+ expectKeyword('new');
+ callee = parseLeftHandSideExpression();
+ args = match('(') ? parseArguments() : [];
+
+ return delegate.createNewExpression(callee, args);
+ }
+
+ function parseLeftHandSideExpressionAllowCall() {
+ var expr, args, property;
+
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+
+ while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) {
+ if (match('(')) {
+ args = parseArguments();
+ expr = delegate.createCallExpression(expr, args);
+ } else if (match('[')) {
+ expr = delegate.createMemberExpression('[', expr, parseComputedMember());
+ } else if (match('.')) {
+ expr = delegate.createMemberExpression('.', expr, parseNonComputedMember());
+ } else {
+ expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral());
+ }
+ }
+
+ return expr;
+ }
+
+
+ function parseLeftHandSideExpression() {
+ var expr, property;
+
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+
+ while (match('.') || match('[') || lookahead.type === Token.Template) {
+ if (match('[')) {
+ expr = delegate.createMemberExpression('[', expr, parseComputedMember());
+ } else if (match('.')) {
+ expr = delegate.createMemberExpression('.', expr, parseNonComputedMember());
+ } else {
+ expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral());
+ }
+ }
+
+ return expr;
+ }
+
+ // 11.3 Postfix Expressions
+
+ function parsePostfixExpression() {
+ var expr = parseLeftHandSideExpressionAllowCall(),
+ token = lookahead;
+
+ if (lookahead.type !== Token.Punctuator) {
+ return expr;
+ }
+
+ if ((match('++') || match('--')) && !peekLineTerminator()) {
+ // 11.3.1, 11.3.2
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant({}, Messages.StrictLHSPostfix);
+ }
+
+ if (!isLeftHandSide(expr)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+
+ token = lex();
+ expr = delegate.createPostfixExpression(token.value, expr);
+ }
+
+ return expr;
+ }
+
+ // 11.4 Unary Operators
+
+ function parseUnaryExpression() {
+ var token, expr;
+
+ if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
+ return parsePostfixExpression();
+ }
+
+ if (match('++') || match('--')) {
+ token = lex();
+ expr = parseUnaryExpression();
+ // 11.4.4, 11.4.5
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant({}, Messages.StrictLHSPrefix);
+ }
+
+ if (!isLeftHandSide(expr)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+
+ return delegate.createUnaryExpression(token.value, expr);
+ }
+
+ if (match('+') || match('-') || match('~') || match('!')) {
+ token = lex();
+ expr = parseUnaryExpression();
+ return delegate.createUnaryExpression(token.value, expr);
+ }
+
+ if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+ token = lex();
+ expr = parseUnaryExpression();
+ expr = delegate.createUnaryExpression(token.value, expr);
+ if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
+ throwErrorTolerant({}, Messages.StrictDelete);
+ }
+ return expr;
+ }
+
+ return parsePostfixExpression();
+ }
+
+ function binaryPrecedence(token, allowIn) {
+ var prec = 0;
+
+ if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
+ return 0;
+ }
+
+ switch (token.value) {
+ case '||':
+ prec = 1;
+ break;
+
+ case '&&':
+ prec = 2;
+ break;
+
+ case '|':
+ prec = 3;
+ break;
+
+ case '^':
+ prec = 4;
+ break;
+
+ case '&':
+ prec = 5;
+ break;
+
+ case '==':
+ case '!=':
+ case '===':
+ case '!==':
+ prec = 6;
+ break;
+
+ case '<':
+ case '>':
+ case '<=':
+ case '>=':
+ case 'instanceof':
+ prec = 7;
+ break;
+
+ case 'in':
+ prec = allowIn ? 7 : 0;
+ break;
+
+ case '<<':
+ case '>>':
+ case '>>>':
+ prec = 8;
+ break;
+
+ case '+':
+ case '-':
+ prec = 9;
+ break;
+
+ case '*':
+ case '/':
+ case '%':
+ prec = 11;
+ break;
+
+ default:
+ break;
+ }
+
+ return prec;
+ }
+
+ // 11.5 Multiplicative Operators
+ // 11.6 Additive Operators
+ // 11.7 Bitwise Shift Operators
+ // 11.8 Relational Operators
+ // 11.9 Equality Operators
+ // 11.10 Binary Bitwise Operators
+ // 11.11 Binary Logical Operators
+
+ function parseBinaryExpression() {
+ var expr, token, prec, previousAllowIn, stack, right, operator, left, i;
+
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+
+ expr = parseUnaryExpression();
+
+ token = lookahead;
+ prec = binaryPrecedence(token, previousAllowIn);
+ if (prec === 0) {
+ return expr;
+ }
+ token.prec = prec;
+ lex();
+
+ stack = [expr, token, parseUnaryExpression()];
+
+ while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) {
+
+ // Reduce: make a binary expression from the three topmost entries.
+ while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
+ right = stack.pop();
+ operator = stack.pop().value;
+ left = stack.pop();
+ stack.push(delegate.createBinaryExpression(operator, left, right));
+ }
+
+ // Shift.
+ token = lex();
+ token.prec = prec;
+ stack.push(token);
+ stack.push(parseUnaryExpression());
+ }
+
+ state.allowIn = previousAllowIn;
+
+ // Final reduce to clean-up the stack.
+ i = stack.length - 1;
+ expr = stack[i];
+ while (i > 1) {
+ expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
+ i -= 2;
+ }
+ return expr;
+ }
+
+
+ // 11.12 Conditional Operator
+
+ function parseConditionalExpression() {
+ var expr, previousAllowIn, consequent, alternate;
+
+ expr = parseBinaryExpression();
+
+ if (match('?')) {
+ lex();
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+ consequent = parseAssignmentExpression();
+ state.allowIn = previousAllowIn;
+ expect(':');
+ alternate = parseAssignmentExpression();
+
+ expr = delegate.createConditionalExpression(expr, consequent, alternate);
+ }
+
+ return expr;
+ }
+
+ // 11.13 Assignment Operators
+
+ function reinterpretAsAssignmentBindingPattern(expr) {
+ var i, len, property, element;
+
+ if (expr.type === Syntax.ObjectExpression) {
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ property = expr.properties[i];
+ if (property.kind !== 'init') {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ reinterpretAsAssignmentBindingPattern(property.value);
+ }
+ } else if (expr.type === Syntax.ArrayExpression) {
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ element = expr.elements[i];
+ if (element) {
+ reinterpretAsAssignmentBindingPattern(element);
+ }
+ }
+ } else if (expr.type === Syntax.Identifier) {
+ if (isRestrictedWord(expr.name)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ } else if (expr.type === Syntax.SpreadElement) {
+ reinterpretAsAssignmentBindingPattern(expr.argument);
+ if (expr.argument.type === Syntax.ObjectPattern) {
+ throwError({}, Messages.ObjectPatternAsSpread);
+ }
+ } else {
+ if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ }
+ }
+
+
+ function reinterpretAsDestructuredParameter(options, expr) {
+ var i, len, property, element;
+
+ if (expr.type === Syntax.ObjectExpression) {
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ property = expr.properties[i];
+ if (property.kind !== 'init') {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ reinterpretAsDestructuredParameter(options, property.value);
+ }
+ } else if (expr.type === Syntax.ArrayExpression) {
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ element = expr.elements[i];
+ if (element) {
+ reinterpretAsDestructuredParameter(options, element);
+ }
+ }
+ } else if (expr.type === Syntax.Identifier) {
+ validateParam(options, expr, expr.name);
+ } else {
+ if (expr.type !== Syntax.MemberExpression) {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ }
+ }
+
+ function reinterpretAsCoverFormalsList(expressions) {
+ var i, len, param, params, defaults, defaultCount, options, rest;
+
+ params = [];
+ defaults = [];
+ defaultCount = 0;
+ rest = null;
+ options = {
+ paramSet: {}
+ };
+
+ for (i = 0, len = expressions.length; i < len; i += 1) {
+ param = expressions[i];
+ if (param.type === Syntax.Identifier) {
+ params.push(param);
+ defaults.push(null);
+ validateParam(options, param, param.name);
+ } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) {
+ reinterpretAsDestructuredParameter(options, param);
+ params.push(param);
+ defaults.push(null);
+ } else if (param.type === Syntax.SpreadElement) {
+ assert(i === len - 1, 'It is guaranteed that SpreadElement is last element by parseExpression');
+ reinterpretAsDestructuredParameter(options, param.argument);
+ rest = param.argument;
+ } else if (param.type === Syntax.AssignmentExpression) {
+ params.push(param.left);
+ defaults.push(param.right);
+ ++defaultCount;
+ validateParam(options, param.left, param.left.name);
+ } else {
+ return null;
+ }
+ }
+
+ if (options.message === Messages.StrictParamDupe) {
+ throwError(
+ strict ? options.stricted : options.firstRestricted,
+ options.message
+ );
+ }
+
+ if (defaultCount === 0) {
+ defaults = [];
+ }
+
+ return {
+ params: params,
+ defaults: defaults,
+ rest: rest,
+ stricted: options.stricted,
+ firstRestricted: options.firstRestricted,
+ message: options.message
+ };
+ }
+
+ function parseArrowFunctionExpression(options) {
+ var previousStrict, previousYieldAllowed, body;
+
+ expect('=>');
+
+ previousStrict = strict;
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ body = parseConciseBody();
+
+ if (strict && options.firstRestricted) {
+ throwError(options.firstRestricted, options.message);
+ }
+ if (strict && options.stricted) {
+ throwErrorTolerant(options.stricted, options.message);
+ }
+
+ strict = previousStrict;
+ state.yieldAllowed = previousYieldAllowed;
+
+ return delegate.createArrowFunctionExpression(options.params, options.defaults, body, options.rest, body.type !== Syntax.BlockStatement);
+ }
+
+ function parseAssignmentExpression() {
+ var expr, token, params, oldParenthesizedCount;
+
+ if (matchKeyword('yield')) {
+ return parseYieldExpression();
+ }
+
+ oldParenthesizedCount = state.parenthesizedCount;
+
+ if (match('(')) {
+ token = lookahead2();
+ if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') {
+ params = parseParams();
+ if (!match('=>')) {
+ throwUnexpected(lex());
+ }
+ return parseArrowFunctionExpression(params);
+ }
+ }
+
+ token = lookahead;
+ expr = parseConditionalExpression();
+
+ if (match('=>') &&
+ (state.parenthesizedCount === oldParenthesizedCount ||
+ state.parenthesizedCount === (oldParenthesizedCount + 1))) {
+ if (expr.type === Syntax.Identifier) {
+ params = reinterpretAsCoverFormalsList([ expr ]);
+ } else if (expr.type === Syntax.SequenceExpression) {
+ params = reinterpretAsCoverFormalsList(expr.expressions);
+ }
+ if (params) {
+ return parseArrowFunctionExpression(params);
+ }
+ }
+
+ if (matchAssign()) {
+ // 11.13.1
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant(token, Messages.StrictLHSAssignment);
+ }
+
+ // ES.next draf 11.13 Runtime Semantics step 1
+ if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) {
+ reinterpretAsAssignmentBindingPattern(expr);
+ } else if (!isLeftHandSide(expr)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+
+ expr = delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression());
+ }
+
+ return expr;
+ }
+
+ // 11.14 Comma Operator
+
+ function parseExpression() {
+ var expr, expressions, sequence, coverFormalsList, spreadFound, oldParenthesizedCount;
+
+ oldParenthesizedCount = state.parenthesizedCount;
+
+ expr = parseAssignmentExpression();
+ expressions = [ expr ];
+
+ if (match(',')) {
+ while (index < length) {
+ if (!match(',')) {
+ break;
+ }
+
+ lex();
+ expr = parseSpreadOrAssignmentExpression();
+ expressions.push(expr);
+
+ if (expr.type === Syntax.SpreadElement) {
+ spreadFound = true;
+ if (!match(')')) {
+ throwError({}, Messages.ElementAfterSpreadElement);
+ }
+ break;
+ }
+ }
+
+ sequence = delegate.createSequenceExpression(expressions);
+ }
+
+ if (match('=>')) {
+ // Do not allow nested parentheses on the LHS of the =>.
+ if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) {
+ expr = expr.type === Syntax.SequenceExpression ? expr.expressions : expressions;
+ coverFormalsList = reinterpretAsCoverFormalsList(expr);
+ if (coverFormalsList) {
+ return parseArrowFunctionExpression(coverFormalsList);
+ }
+ }
+ throwUnexpected(lex());
+ }
+
+ if (spreadFound && lookahead2().value !== '=>') {
+ throwError({}, Messages.IllegalSpread);
+ }
+
+ return sequence || expr;
+ }
+
+ // 12.1 Block
+
+ function parseStatementList() {
+ var list = [],
+ statement;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ statement = parseSourceElement();
+ if (typeof statement === 'undefined') {
+ break;
+ }
+ list.push(statement);
+ }
+
+ return list;
+ }
+
+ function parseBlock() {
+ var block;
+
+ expect('{');
+
+ block = parseStatementList();
+
+ expect('}');
+
+ return delegate.createBlockStatement(block);
+ }
+
+ // 12.2 Variable Statement
+
+ function parseTypeAnnotation(dontExpectColon) {
+ var typeIdentifier = null, paramTypes = null, returnType = null,
+ nullable = false;
+
+ if (!dontExpectColon) {
+ expect(':');
+ }
+
+ if (match('?')) {
+ lex();
+ nullable = true;
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ typeIdentifier = parseVariableIdentifier();
+ }
+
+ if (match('(')) {
+ lex();
+ paramTypes = [];
+ while (lookahead.type === Token.Identifier || match('?')) {
+ paramTypes.push(parseTypeAnnotation(true));
+ if (!match(')')) {
+ expect(',');
+ }
+ }
+ expect(')');
+ expect('=>');
+
+ if (matchKeyword('void')) {
+ lex();
+ } else {
+ returnType = parseTypeAnnotation(true);
+ }
+ }
+
+ return delegate.createTypeAnnotation(
+ typeIdentifier,
+ paramTypes,
+ returnType,
+ nullable
+ );
+ }
+
+ function parseVariableIdentifier() {
+ var token = lex();
+
+ if (token.type !== Token.Identifier) {
+ throwUnexpected(token);
+ }
+
+ return delegate.createIdentifier(token.value);
+ }
+
+ function parseTypeAnnotatableIdentifier() {
+ var ident = parseVariableIdentifier();
+
+ if (match(':')) {
+ return delegate.createTypeAnnotatedIdentifier(ident, parseTypeAnnotation());
+ }
+
+ return ident;
+ }
+
+ function parseVariableDeclaration(kind) {
+ var id,
+ init = null;
+ if (match('{')) {
+ id = parseObjectInitialiser();
+ reinterpretAsAssignmentBindingPattern(id);
+ } else if (match('[')) {
+ id = parseArrayInitialiser();
+ reinterpretAsAssignmentBindingPattern(id);
+ } else {
+ id = state.allowKeyword ? parseNonComputedProperty() : parseTypeAnnotatableIdentifier();
+ // 12.2.1
+ if (strict && isRestrictedWord(id.name)) {
+ throwErrorTolerant({}, Messages.StrictVarName);
+ }
+ }
+
+ if (kind === 'const') {
+ if (!match('=')) {
+ throwError({}, Messages.NoUnintializedConst);
+ }
+ expect('=');
+ init = parseAssignmentExpression();
+ } else if (match('=')) {
+ lex();
+ init = parseAssignmentExpression();
+ }
+
+ return delegate.createVariableDeclarator(id, init);
+ }
+
+ function parseVariableDeclarationList(kind) {
+ var list = [];
+
+ do {
+ list.push(parseVariableDeclaration(kind));
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ } while (index < length);
+
+ return list;
+ }
+
+ function parseVariableStatement() {
+ var declarations;
+
+ expectKeyword('var');
+
+ declarations = parseVariableDeclarationList();
+
+ consumeSemicolon();
+
+ return delegate.createVariableDeclaration(declarations, 'var');
+ }
+
+ // kind may be `const` or `let`
+ // Both are experimental and not in the specification yet.
+ // see http://wiki.ecmascript.org/doku.php?id=harmony:const
+ // and http://wiki.ecmascript.org/doku.php?id=harmony:let
+ function parseConstLetDeclaration(kind) {
+ var declarations;
+
+ expectKeyword(kind);
+
+ declarations = parseVariableDeclarationList(kind);
+
+ consumeSemicolon();
+
+ return delegate.createVariableDeclaration(declarations, kind);
+ }
+
+ // http://wiki.ecmascript.org/doku.php?id=harmony:modules
+
+ function parseModuleDeclaration() {
+ var id, src, body;
+
+ lex(); // 'module'
+
+ if (peekLineTerminator()) {
+ throwError({}, Messages.NewlineAfterModule);
+ }
+
+ switch (lookahead.type) {
+
+ case Token.StringLiteral:
+ id = parsePrimaryExpression();
+ body = parseModuleBlock();
+ src = null;
+ break;
+
+ case Token.Identifier:
+ id = parseVariableIdentifier();
+ body = null;
+ if (!matchContextualKeyword('from')) {
+ throwUnexpected(lex());
+ }
+ lex();
+ src = parsePrimaryExpression();
+ if (src.type !== Syntax.Literal) {
+ throwError({}, Messages.InvalidModuleSpecifier);
+ }
+ break;
+ }
+
+ consumeSemicolon();
+ return delegate.createModuleDeclaration(id, src, body);
+ }
+
+ function parseExportBatchSpecifier() {
+ expect('*');
+ return delegate.createExportBatchSpecifier();
+ }
+
+ function parseExportSpecifier() {
+ var id, name = null;
+
+ id = parseVariableIdentifier();
+ if (matchContextualKeyword('as')) {
+ lex();
+ name = parseNonComputedProperty();
+ }
+
+ return delegate.createExportSpecifier(id, name);
+ }
+
+ function parseExportDeclaration() {
+ var previousAllowKeyword, decl, def, src, specifiers;
+
+ expectKeyword('export');
+
+ if (lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'let':
+ case 'const':
+ case 'var':
+ case 'class':
+ case 'function':
+ return delegate.createExportDeclaration(parseSourceElement(), null, null);
+ }
+ }
+
+ if (isIdentifierName(lookahead)) {
+ previousAllowKeyword = state.allowKeyword;
+ state.allowKeyword = true;
+ decl = parseVariableDeclarationList('let');
+ state.allowKeyword = previousAllowKeyword;
+ return delegate.createExportDeclaration(decl, null, null);
+ }
+
+ specifiers = [];
+ src = null;
+
+ if (match('*')) {
+ specifiers.push(parseExportBatchSpecifier());
+ } else {
+ expect('{');
+ do {
+ specifiers.push(parseExportSpecifier());
+ } while (match(',') && lex());
+ expect('}');
+ }
+
+ if (matchContextualKeyword('from')) {
+ lex();
+ src = parsePrimaryExpression();
+ if (src.type !== Syntax.Literal) {
+ throwError({}, Messages.InvalidModuleSpecifier);
+ }
+ }
+
+ consumeSemicolon();
+
+ return delegate.createExportDeclaration(null, specifiers, src);
+ }
+
+ function parseImportDeclaration() {
+ var specifiers, kind, src;
+
+ expectKeyword('import');
+ specifiers = [];
+
+ if (isIdentifierName(lookahead)) {
+ kind = 'default';
+ specifiers.push(parseImportSpecifier());
+
+ if (!matchContextualKeyword('from')) {
+ throwError({}, Messages.NoFromAfterImport);
+ }
+ lex();
+ } else if (match('{')) {
+ kind = 'named';
+ lex();
+ do {
+ specifiers.push(parseImportSpecifier());
+ } while (match(',') && lex());
+ expect('}');
+
+ if (!matchContextualKeyword('from')) {
+ throwError({}, Messages.NoFromAfterImport);
+ }
+ lex();
+ }
+
+ src = parsePrimaryExpression();
+ if (src.type !== Syntax.Literal) {
+ throwError({}, Messages.InvalidModuleSpecifier);
+ }
+
+ consumeSemicolon();
+
+ return delegate.createImportDeclaration(specifiers, kind, src);
+ }
+
+ function parseImportSpecifier() {
+ var id, name = null;
+
+ id = parseNonComputedProperty();
+ if (matchContextualKeyword('as')) {
+ lex();
+ name = parseVariableIdentifier();
+ }
+
+ return delegate.createImportSpecifier(id, name);
+ }
+
+ // 12.3 Empty Statement
+
+ function parseEmptyStatement() {
+ expect(';');
+ return delegate.createEmptyStatement();
+ }
+
+ // 12.4 Expression Statement
+
+ function parseExpressionStatement() {
+ var expr = parseExpression();
+ consumeSemicolon();
+ return delegate.createExpressionStatement(expr);
+ }
+
+ // 12.5 If statement
+
+ function parseIfStatement() {
+ var test, consequent, alternate;
+
+ expectKeyword('if');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ consequent = parseStatement();
+
+ if (matchKeyword('else')) {
+ lex();
+ alternate = parseStatement();
+ } else {
+ alternate = null;
+ }
+
+ return delegate.createIfStatement(test, consequent, alternate);
+ }
+
+ // 12.6 Iteration Statements
+
+ function parseDoWhileStatement() {
+ var body, test, oldInIteration;
+
+ expectKeyword('do');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ if (match(';')) {
+ lex();
+ }
+
+ return delegate.createDoWhileStatement(body, test);
+ }
+
+ function parseWhileStatement() {
+ var test, body, oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ return delegate.createWhileStatement(test, body);
+ }
+
+ function parseForVariableDeclaration() {
+ var token = lex(),
+ declarations = parseVariableDeclarationList();
+
+ return delegate.createVariableDeclaration(declarations, token.value);
+ }
+
+ function parseForStatement(opts) {
+ var init, test, update, left, right, body, operator, oldInIteration;
+ init = test = update = null;
+ expectKeyword('for');
+
+ // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each
+ if (matchContextualKeyword('each')) {
+ throwError({}, Messages.EachNotAllowed);
+ }
+
+ expect('(');
+
+ if (match(';')) {
+ lex();
+ } else {
+ if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) {
+ state.allowIn = false;
+ init = parseForVariableDeclaration();
+ state.allowIn = true;
+
+ if (init.declarations.length === 1) {
+ if (matchKeyword('in') || matchContextualKeyword('of')) {
+ operator = lookahead;
+ if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) {
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ }
+ }
+ } else {
+ state.allowIn = false;
+ init = parseExpression();
+ state.allowIn = true;
+
+ if (matchContextualKeyword('of')) {
+ operator = lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else if (matchKeyword('in')) {
+ // LeftHandSideExpression
+ if (!isAssignableLeftHandSide(init)) {
+ throwError({}, Messages.InvalidLHSInForIn);
+ }
+ operator = lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ }
+
+ if (typeof left === 'undefined') {
+ expect(';');
+ }
+ }
+
+ if (typeof left === 'undefined') {
+
+ if (!match(';')) {
+ test = parseExpression();
+ }
+ expect(';');
+
+ if (!match(')')) {
+ update = parseExpression();
+ }
+ }
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ if (!(opts !== undefined && opts.ignoreBody)) {
+ body = parseStatement();
+ }
+
+ state.inIteration = oldInIteration;
+
+ if (typeof left === 'undefined') {
+ return delegate.createForStatement(init, test, update, body);
+ }
+
+ if (operator.value === 'in') {
+ return delegate.createForInStatement(left, right, body);
+ }
+ return delegate.createForOfStatement(left, right, body);
+ }
+
+ // 12.7 The continue statement
+
+ function parseContinueStatement() {
+ var label = null, key;
+
+ expectKeyword('continue');
+
+ // Optimize the most common form: 'continue;'.
+ if (source.charCodeAt(index) === 59) {
+ lex();
+
+ if (!state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(null);
+ }
+
+ if (peekLineTerminator()) {
+ if (!state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !state.inIteration) {
+ throwError({}, Messages.IllegalContinue);
+ }
+
+ return delegate.createContinueStatement(label);
+ }
+
+ // 12.8 The break statement
+
+ function parseBreakStatement() {
+ var label = null, key;
+
+ expectKeyword('break');
+
+ // Catch the very common case first: immediately a semicolon (char #59).
+ if (source.charCodeAt(index) === 59) {
+ lex();
+
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(null);
+ }
+
+ if (peekLineTerminator()) {
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !(state.inIteration || state.inSwitch)) {
+ throwError({}, Messages.IllegalBreak);
+ }
+
+ return delegate.createBreakStatement(label);
+ }
+
+ // 12.9 The return statement
+
+ function parseReturnStatement() {
+ var argument = null;
+
+ expectKeyword('return');
+
+ if (!state.inFunctionBody) {
+ throwErrorTolerant({}, Messages.IllegalReturn);
+ }
+
+ // 'return' followed by a space and an identifier is very common.
+ if (source.charCodeAt(index) === 32) {
+ if (isIdentifierStart(source.charCodeAt(index + 1))) {
+ argument = parseExpression();
+ consumeSemicolon();
+ return delegate.createReturnStatement(argument);
+ }
+ }
+
+ if (peekLineTerminator()) {
+ return delegate.createReturnStatement(null);
+ }
+
+ if (!match(';')) {
+ if (!match('}') && lookahead.type !== Token.EOF) {
+ argument = parseExpression();
+ }
+ }
+
+ consumeSemicolon();
+
+ return delegate.createReturnStatement(argument);
+ }
+
+ // 12.10 The with statement
+
+ function parseWithStatement() {
+ var object, body;
+
+ if (strict) {
+ throwErrorTolerant({}, Messages.StrictModeWith);
+ }
+
+ expectKeyword('with');
+
+ expect('(');
+
+ object = parseExpression();
+
+ expect(')');
+
+ body = parseStatement();
+
+ return delegate.createWithStatement(object, body);
+ }
+
+ // 12.10 The swith statement
+
+ function parseSwitchCase() {
+ var test,
+ consequent = [],
+ sourceElement;
+
+ if (matchKeyword('default')) {
+ lex();
+ test = null;
+ } else {
+ expectKeyword('case');
+ test = parseExpression();
+ }
+ expect(':');
+
+ while (index < length) {
+ if (match('}') || matchKeyword('default') || matchKeyword('case')) {
+ break;
+ }
+ sourceElement = parseSourceElement();
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ consequent.push(sourceElement);
+ }
+
+ return delegate.createSwitchCase(test, consequent);
+ }
+
+ function parseSwitchStatement() {
+ var discriminant, cases, clause, oldInSwitch, defaultFound;
+
+ expectKeyword('switch');
+
+ expect('(');
+
+ discriminant = parseExpression();
+
+ expect(')');
+
+ expect('{');
+
+ cases = [];
+
+ if (match('}')) {
+ lex();
+ return delegate.createSwitchStatement(discriminant, cases);
+ }
+
+ oldInSwitch = state.inSwitch;
+ state.inSwitch = true;
+ defaultFound = false;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ clause = parseSwitchCase();
+ if (clause.test === null) {
+ if (defaultFound) {
+ throwError({}, Messages.MultipleDefaultsInSwitch);
+ }
+ defaultFound = true;
+ }
+ cases.push(clause);
+ }
+
+ state.inSwitch = oldInSwitch;
+
+ expect('}');
+
+ return delegate.createSwitchStatement(discriminant, cases);
+ }
+
+ // 12.13 The throw statement
+
+ function parseThrowStatement() {
+ var argument;
+
+ expectKeyword('throw');
+
+ if (peekLineTerminator()) {
+ throwError({}, Messages.NewlineAfterThrow);
+ }
+
+ argument = parseExpression();
+
+ consumeSemicolon();
+
+ return delegate.createThrowStatement(argument);
+ }
+
+ // 12.14 The try statement
+
+ function parseCatchClause() {
+ var param, body;
+
+ expectKeyword('catch');
+
+ expect('(');
+ if (match(')')) {
+ throwUnexpected(lookahead);
+ }
+
+ param = parseExpression();
+ // 12.14.1
+ if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
+ throwErrorTolerant({}, Messages.StrictCatchVariable);
+ }
+
+ expect(')');
+ body = parseBlock();
+ return delegate.createCatchClause(param, body);
+ }
+
+ function parseTryStatement() {
+ var block, handlers = [], finalizer = null;
+
+ expectKeyword('try');
+
+ block = parseBlock();
+
+ if (matchKeyword('catch')) {
+ handlers.push(parseCatchClause());
+ }
+
+ if (matchKeyword('finally')) {
+ lex();
+ finalizer = parseBlock();
+ }
+
+ if (handlers.length === 0 && !finalizer) {
+ throwError({}, Messages.NoCatchOrFinally);
+ }
+
+ return delegate.createTryStatement(block, [], handlers, finalizer);
+ }
+
+ // 12.15 The debugger statement
+
+ function parseDebuggerStatement() {
+ expectKeyword('debugger');
+
+ consumeSemicolon();
+
+ return delegate.createDebuggerStatement();
+ }
+
+ // 12 Statements
+
+ function parseStatement() {
+ var type = lookahead.type,
+ expr,
+ labeledBody,
+ key;
+
+ if (type === Token.EOF) {
+ throwUnexpected(lookahead);
+ }
+
+ if (type === Token.Punctuator) {
+ switch (lookahead.value) {
+ case ';':
+ return parseEmptyStatement();
+ case '{':
+ return parseBlock();
+ case '(':
+ return parseExpressionStatement();
+ default:
+ break;
+ }
+ }
+
+ if (type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'break':
+ return parseBreakStatement();
+ case 'continue':
+ return parseContinueStatement();
+ case 'debugger':
+ return parseDebuggerStatement();
+ case 'do':
+ return parseDoWhileStatement();
+ case 'for':
+ return parseForStatement();
+ case 'function':
+ return parseFunctionDeclaration();
+ case 'class':
+ return parseClassDeclaration();
+ case 'if':
+ return parseIfStatement();
+ case 'return':
+ return parseReturnStatement();
+ case 'switch':
+ return parseSwitchStatement();
+ case 'throw':
+ return parseThrowStatement();
+ case 'try':
+ return parseTryStatement();
+ case 'var':
+ return parseVariableStatement();
+ case 'while':
+ return parseWhileStatement();
+ case 'with':
+ return parseWithStatement();
+ default:
+ break;
+ }
+ }
+
+ expr = parseExpression();
+
+ // 12.12 Labelled Statements
+ if ((expr.type === Syntax.Identifier) && match(':')) {
+ lex();
+
+ key = '$' + expr.name;
+ if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError({}, Messages.Redeclaration, 'Label', expr.name);
+ }
+
+ state.labelSet[key] = true;
+ labeledBody = parseStatement();
+ delete state.labelSet[key];
+ return delegate.createLabeledStatement(expr, labeledBody);
+ }
+
+ consumeSemicolon();
+
+ return delegate.createExpressionStatement(expr);
+ }
+
+ // 13 Function Definition
+
+ function parseConciseBody() {
+ if (match('{')) {
+ return parseFunctionSourceElements();
+ }
+ return parseAssignmentExpression();
+ }
+
+ function parseFunctionSourceElements() {
+ var sourceElement, sourceElements = [], token, directive, firstRestricted,
+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount;
+
+ expect('{');
+
+ while (index < length) {
+ if (lookahead.type !== Token.StringLiteral) {
+ break;
+ }
+ token = lookahead;
+
+ sourceElement = parseSourceElement();
+ sourceElements.push(sourceElement);
+ if (sourceElement.expression.type !== Syntax.Literal) {
+ // this is not directive
+ break;
+ }
+ directive = source.slice(token.range[0] + 1, token.range[1] - 1);
+ if (directive === 'use strict') {
+ strict = true;
+ if (firstRestricted) {
+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
+ }
+ } else {
+ if (!firstRestricted && token.octal) {
+ firstRestricted = token;
+ }
+ }
+ }
+
+ oldLabelSet = state.labelSet;
+ oldInIteration = state.inIteration;
+ oldInSwitch = state.inSwitch;
+ oldInFunctionBody = state.inFunctionBody;
+ oldParenthesizedCount = state.parenthesizedCount;
+
+ state.labelSet = {};
+ state.inIteration = false;
+ state.inSwitch = false;
+ state.inFunctionBody = true;
+ state.parenthesizedCount = 0;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ sourceElement = parseSourceElement();
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ sourceElements.push(sourceElement);
+ }
+
+ expect('}');
+
+ state.labelSet = oldLabelSet;
+ state.inIteration = oldInIteration;
+ state.inSwitch = oldInSwitch;
+ state.inFunctionBody = oldInFunctionBody;
+ state.parenthesizedCount = oldParenthesizedCount;
+
+ return delegate.createBlockStatement(sourceElements);
+ }
+
+ function validateParam(options, param, name) {
+ var key = '$' + name;
+ if (strict) {
+ if (isRestrictedWord(name)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamName;
+ }
+ if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ } else if (!options.firstRestricted) {
+ if (isRestrictedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamName;
+ } else if (isStrictModeReservedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictReservedWord;
+ } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ }
+ options.paramSet[key] = true;
+ }
+
+ function parseParam(options) {
+ var token, rest, param, def;
+
+ token = lookahead;
+ if (token.value === '...') {
+ token = lex();
+ rest = true;
+ }
+
+ if (match('[')) {
+ param = parseArrayInitialiser();
+ reinterpretAsDestructuredParameter(options, param);
+ } else if (match('{')) {
+ if (rest) {
+ throwError({}, Messages.ObjectPatternAsRestParameter);
+ }
+ param = parseObjectInitialiser();
+ reinterpretAsDestructuredParameter(options, param);
+ } else {
+ // Typing rest params is awkward, so punting on that for now
+ param = rest
+ ? parseVariableIdentifier()
+ : parseTypeAnnotatableIdentifier();
+ validateParam(options, token, token.value);
+ if (match('=')) {
+ if (rest) {
+ throwErrorTolerant(lookahead, Messages.DefaultRestParameter);
+ }
+ lex();
+ def = parseAssignmentExpression();
+ ++options.defaultCount;
+ }
+ }
+
+ if (rest) {
+ if (!match(')')) {
+ throwError({}, Messages.ParameterAfterRestParameter);
+ }
+ options.rest = param;
+ return false;
+ }
+
+ options.params.push(param);
+ options.defaults.push(def);
+ return !match(')');
+ }
+
+ function parseParams(firstRestricted) {
+ var options;
+
+ options = {
+ params: [],
+ defaultCount: 0,
+ defaults: [],
+ rest: null,
+ firstRestricted: firstRestricted
+ };
+
+ expect('(');
+
+ if (!match(')')) {
+ options.paramSet = {};
+ while (index < length) {
+ if (!parseParam(options)) {
+ break;
+ }
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ if (options.defaultCount === 0) {
+ options.defaults = [];
+ }
+
+ if (match(':')) {
+ options.returnTypeAnnotation = parseTypeAnnotation();
+ }
+
+ return options;
+ }
+
+ function parseFunctionDeclaration() {
+ var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator;
+
+ expectKeyword('function');
+
+ generator = false;
+ if (match('*')) {
+ lex();
+ generator = true;
+ }
+
+ token = lookahead;
+
+ id = parseVariableIdentifier();
+
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = generator;
+
+ body = parseFunctionSourceElements();
+
+ if (strict && firstRestricted) {
+ throwError(firstRestricted, message);
+ }
+ if (strict && tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, message);
+ }
+ if (state.yieldAllowed && !state.yieldFound) {
+ throwErrorTolerant({}, Messages.NoYieldInGenerator);
+ }
+ strict = previousStrict;
+ state.yieldAllowed = previousYieldAllowed;
+
+ return delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false,
+ tmp.returnTypeAnnotation);
+ }
+
+ function parseFunctionExpression() {
+ var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator;
+
+ expectKeyword('function');
+
+ generator = false;
+
+ if (match('*')) {
+ lex();
+ generator = true;
+ }
+
+ if (!match('(')) {
+ token = lookahead;
+ id = parseVariableIdentifier();
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ throwErrorTolerant(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = generator;
+
+ body = parseFunctionSourceElements();
+
+ if (strict && firstRestricted) {
+ throwError(firstRestricted, message);
+ }
+ if (strict && tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, message);
+ }
+ if (state.yieldAllowed && !state.yieldFound) {
+ throwErrorTolerant({}, Messages.NoYieldInGenerator);
+ }
+ strict = previousStrict;
+ state.yieldAllowed = previousYieldAllowed;
+
+ return delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false,
+ tmp.returnTypeAnnotation);
+ }
+
+ function parseYieldExpression() {
+ var delegateFlag, expr;
+
+ expectKeyword('yield');
+
+ if (!state.yieldAllowed) {
+ throwErrorTolerant({}, Messages.IllegalYield);
+ }
+
+ delegateFlag = false;
+ if (match('*')) {
+ lex();
+ delegateFlag = true;
+ }
+
+ expr = parseAssignmentExpression();
+ state.yieldFound = true;
+
+ return delegate.createYieldExpression(expr, delegateFlag);
+ }
+
+ // 14 Classes
+
+ function parseMethodDefinition(existingPropNames) {
+ var token, key, param, propType, isValidDuplicateProp = false;
+
+ if (lookahead.value === 'static') {
+ propType = ClassPropertyType["static"];
+ lex();
+ } else {
+ propType = ClassPropertyType.prototype;
+ }
+
+ if (match('*')) {
+ lex();
+ return delegate.createMethodDefinition(
+ propType,
+ '',
+ parseObjectPropertyKey(),
+ parsePropertyMethodFunction({ generator: true })
+ );
+ }
+
+ token = lookahead;
+ key = parseObjectPropertyKey();
+
+ if (token.value === 'get' && !match('(')) {
+ key = parseObjectPropertyKey();
+
+ // It is a syntax error if any other properties have a name
+ // duplicating this one unless they are a setter
+ if (existingPropNames[propType].hasOwnProperty(key.name)) {
+ isValidDuplicateProp =
+ // There isn't already a getter for this prop
+ existingPropNames[propType][key.name].get === undefined
+ // There isn't already a data prop by this name
+ && existingPropNames[propType][key.name].data === undefined
+ // The only existing prop by this name is a setter
+ && existingPropNames[propType][key.name].set !== undefined;
+ if (!isValidDuplicateProp) {
+ throwError(key, Messages.IllegalDuplicateClassProperty);
+ }
+ } else {
+ existingPropNames[propType][key.name] = {};
+ }
+ existingPropNames[propType][key.name].get = true;
+
+ expect('(');
+ expect(')');
+ return delegate.createMethodDefinition(
+ propType,
+ 'get',
+ key,
+ parsePropertyFunction({ generator: false })
+ );
+ }
+ if (token.value === 'set' && !match('(')) {
+ key = parseObjectPropertyKey();
+
+ // It is a syntax error if any other properties have a name
+ // duplicating this one unless they are a getter
+ if (existingPropNames[propType].hasOwnProperty(key.name)) {
+ isValidDuplicateProp =
+ // There isn't already a setter for this prop
+ existingPropNames[propType][key.name].set === undefined
+ // There isn't already a data prop by this name
+ && existingPropNames[propType][key.name].data === undefined
+ // The only existing prop by this name is a getter
+ && existingPropNames[propType][key.name].get !== undefined;
+ if (!isValidDuplicateProp) {
+ throwError(key, Messages.IllegalDuplicateClassProperty);
+ }
+ } else {
+ existingPropNames[propType][key.name] = {};
+ }
+ existingPropNames[propType][key.name].set = true;
+
+ expect('(');
+ token = lookahead;
+ param = [ parseTypeAnnotatableIdentifier() ];
+ expect(')');
+ return delegate.createMethodDefinition(
+ propType,
+ 'set',
+ key,
+ parsePropertyFunction({ params: param, generator: false, name: token })
+ );
+ }
+
+ // It is a syntax error if any other properties have the same name as a
+ // non-getter, non-setter method
+ if (existingPropNames[propType].hasOwnProperty(key.name)) {
+ throwError(key, Messages.IllegalDuplicateClassProperty);
+ } else {
+ existingPropNames[propType][key.name] = {};
+ }
+ existingPropNames[propType][key.name].data = true;
+
+ return delegate.createMethodDefinition(
+ propType,
+ '',
+ key,
+ parsePropertyMethodFunction({ generator: false })
+ );
+ }
+
+ function parseClassElement(existingProps) {
+ if (match(';')) {
+ lex();
+ return;
+ }
+ return parseMethodDefinition(existingProps);
+ }
+
+ function parseClassBody() {
+ var classElement, classElements = [], existingProps = {};
+
+ existingProps[ClassPropertyType["static"]] = {};
+ existingProps[ClassPropertyType.prototype] = {};
+
+ expect('{');
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ classElement = parseClassElement(existingProps);
+
+ if (typeof classElement !== 'undefined') {
+ classElements.push(classElement);
+ }
+ }
+
+ expect('}');
+
+ return delegate.createClassBody(classElements);
+ }
+
+ function parseClassExpression() {
+ var id, previousYieldAllowed, superClass = null;
+
+ expectKeyword('class');
+
+ if (!matchKeyword('extends') && !match('{')) {
+ id = parseVariableIdentifier();
+ }
+
+ if (matchKeyword('extends')) {
+ expectKeyword('extends');
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ superClass = parseAssignmentExpression();
+ state.yieldAllowed = previousYieldAllowed;
+ }
+
+ return delegate.createClassExpression(id, superClass, parseClassBody());
+ }
+
+ function parseClassDeclaration() {
+ var id, previousYieldAllowed, superClass = null;
+
+ expectKeyword('class');
+
+ id = parseVariableIdentifier();
+
+ if (matchKeyword('extends')) {
+ expectKeyword('extends');
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ superClass = parseAssignmentExpression();
+ state.yieldAllowed = previousYieldAllowed;
+ }
+
+ return delegate.createClassDeclaration(id, superClass, parseClassBody());
+ }
+
+ // 15 Program
+
+ function matchModuleDeclaration() {
+ var id;
+ if (matchContextualKeyword('module')) {
+ id = lookahead2();
+ return id.type === Token.StringLiteral || id.type === Token.Identifier;
+ }
+ return false;
+ }
+
+ function parseSourceElement() {
+ if (lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'const':
+ case 'let':
+ return parseConstLetDeclaration(lookahead.value);
+ case 'function':
+ return parseFunctionDeclaration();
+ case 'export':
+ return parseExportDeclaration();
+ case 'import':
+ return parseImportDeclaration();
+ default:
+ return parseStatement();
+ }
+ }
+
+ if (matchModuleDeclaration()) {
+ throwError({}, Messages.NestedModule);
+ }
+
+ if (lookahead.type !== Token.EOF) {
+ return parseStatement();
+ }
+ }
+
+ function parseProgramElement() {
+ if (lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'export':
+ return parseExportDeclaration();
+ case 'import':
+ return parseImportDeclaration();
+ }
+ }
+
+ if (matchModuleDeclaration()) {
+ return parseModuleDeclaration();
+ }
+
+ return parseSourceElement();
+ }
+
+ function parseProgramElements() {
+ var sourceElement, sourceElements = [], token, directive, firstRestricted;
+
+ while (index < length) {
+ token = lookahead;
+ if (token.type !== Token.StringLiteral) {
+ break;
+ }
+
+ sourceElement = parseProgramElement();
+ sourceElements.push(sourceElement);
+ if (sourceElement.expression.type !== Syntax.Literal) {
+ // this is not directive
+ break;
+ }
+ directive = source.slice(token.range[0] + 1, token.range[1] - 1);
+ if (directive === 'use strict') {
+ strict = true;
+ if (firstRestricted) {
+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
+ }
+ } else {
+ if (!firstRestricted && token.octal) {
+ firstRestricted = token;
+ }
+ }
+ }
+
+ while (index < length) {
+ sourceElement = parseProgramElement();
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ sourceElements.push(sourceElement);
+ }
+ return sourceElements;
+ }
+
+ function parseModuleElement() {
+ return parseSourceElement();
+ }
+
+ function parseModuleElements() {
+ var list = [],
+ statement;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ statement = parseModuleElement();
+ if (typeof statement === 'undefined') {
+ break;
+ }
+ list.push(statement);
+ }
+
+ return list;
+ }
+
+ function parseModuleBlock() {
+ var block;
+
+ expect('{');
+
+ block = parseModuleElements();
+
+ expect('}');
+
+ return delegate.createBlockStatement(block);
+ }
+
+ function parseProgram() {
+ var body;
+ strict = false;
+ peek();
+ body = parseProgramElements();
+ return delegate.createProgram(body);
+ }
+
+ // The following functions are needed only when the option to preserve
+ // the comments is active.
+
+ function addComment(type, value, start, end, loc) {
+ assert(typeof start === 'number', 'Comment must have valid position');
+
+ // Because the way the actual token is scanned, often the comments
+ // (if any) are skipped twice during the lexical analysis.
+ // Thus, we need to skip adding a comment if the comment array already
+ // handled it.
+ if (extra.comments.length > 0) {
+ if (extra.comments[extra.comments.length - 1].range[1] > start) {
+ return;
+ }
+ }
+
+ extra.comments.push({
+ type: type,
+ value: value,
+ range: [start, end],
+ loc: loc
+ });
+ }
+
+ function scanComment() {
+ var comment, ch, loc, start, blockComment, lineComment;
+
+ comment = '';
+ blockComment = false;
+ lineComment = false;
+
+ while (index < length) {
+ ch = source[index];
+
+ if (lineComment) {
+ ch = source[index++];
+ if (isLineTerminator(ch.charCodeAt(0))) {
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart - 1
+ };
+ lineComment = false;
+ addComment('Line', comment, start, index - 1, loc);
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ comment = '';
+ } else if (index >= length) {
+ lineComment = false;
+ comment += ch;
+ loc.end = {
+ line: lineNumber,
+ column: length - lineStart
+ };
+ addComment('Line', comment, start, length, loc);
+ } else {
+ comment += ch;
+ }
+ } else if (blockComment) {
+ if (isLineTerminator(ch.charCodeAt(0))) {
+ if (ch === '\r' && source[index + 1] === '\n') {
+ ++index;
+ comment += '\r\n';
+ } else {
+ comment += ch;
+ }
+ ++lineNumber;
+ ++index;
+ lineStart = index;
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else {
+ ch = source[index++];
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ comment += ch;
+ if (ch === '*') {
+ ch = source[index];
+ if (ch === '/') {
+ comment = comment.substr(0, comment.length - 1);
+ blockComment = false;
+ ++index;
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+ addComment('Block', comment, start, index, loc);
+ comment = '';
+ }
+ }
+ }
+ } else if (ch === '/') {
+ ch = source[index + 1];
+ if (ch === '/') {
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+ start = index;
+ index += 2;
+ lineComment = true;
+ if (index >= length) {
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+ lineComment = false;
+ addComment('Line', comment, start, index, loc);
+ }
+ } else if (ch === '*') {
+ start = index;
+ index += 2;
+ blockComment = true;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart - 2
+ }
+ };
+ if (index >= length) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ } else {
+ break;
+ }
+ } else if (isWhiteSpace(ch.charCodeAt(0))) {
+ ++index;
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ ++index;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ ++lineNumber;
+ lineStart = index;
+ } else {
+ break;
+ }
+ }
+ }
+
+ function filterCommentLocation() {
+ var i, entry, comment, comments = [];
+
+ for (i = 0; i < extra.comments.length; ++i) {
+ entry = extra.comments[i];
+ comment = {
+ type: entry.type,
+ value: entry.value
+ };
+ if (extra.range) {
+ comment.range = entry.range;
+ }
+ if (extra.loc) {
+ comment.loc = entry.loc;
+ }
+ comments.push(comment);
+ }
+
+ extra.comments = comments;
+ }
+
+ // 16 XJS
+
+ XHTMLEntities = {
+ quot: '\u0022',
+ amp: '&',
+ apos: "\u0027",
+ lt: "<",
+ gt: ">",
+ nbsp: "\u00A0",
+ iexcl: "\u00A1",
+ cent: "\u00A2",
+ pound: "\u00A3",
+ curren: "\u00A4",
+ yen: "\u00A5",
+ brvbar: "\u00A6",
+ sect: "\u00A7",
+ uml: "\u00A8",
+ copy: "\u00A9",
+ ordf: "\u00AA",
+ laquo: "\u00AB",
+ not: "\u00AC",
+ shy: "\u00AD",
+ reg: "\u00AE",
+ macr: "\u00AF",
+ deg: "\u00B0",
+ plusmn: "\u00B1",
+ sup2: "\u00B2",
+ sup3: "\u00B3",
+ acute: "\u00B4",
+ micro: "\u00B5",
+ para: "\u00B6",
+ middot: "\u00B7",
+ cedil: "\u00B8",
+ sup1: "\u00B9",
+ ordm: "\u00BA",
+ raquo: "\u00BB",
+ frac14: "\u00BC",
+ frac12: "\u00BD",
+ frac34: "\u00BE",
+ iquest: "\u00BF",
+ Agrave: "\u00C0",
+ Aacute: "\u00C1",
+ Acirc: "\u00C2",
+ Atilde: "\u00C3",
+ Auml: "\u00C4",
+ Aring: "\u00C5",
+ AElig: "\u00C6",
+ Ccedil: "\u00C7",
+ Egrave: "\u00C8",
+ Eacute: "\u00C9",
+ Ecirc: "\u00CA",
+ Euml: "\u00CB",
+ Igrave: "\u00CC",
+ Iacute: "\u00CD",
+ Icirc: "\u00CE",
+ Iuml: "\u00CF",
+ ETH: "\u00D0",
+ Ntilde: "\u00D1",
+ Ograve: "\u00D2",
+ Oacute: "\u00D3",
+ Ocirc: "\u00D4",
+ Otilde: "\u00D5",
+ Ouml: "\u00D6",
+ times: "\u00D7",
+ Oslash: "\u00D8",
+ Ugrave: "\u00D9",
+ Uacute: "\u00DA",
+ Ucirc: "\u00DB",
+ Uuml: "\u00DC",
+ Yacute: "\u00DD",
+ THORN: "\u00DE",
+ szlig: "\u00DF",
+ agrave: "\u00E0",
+ aacute: "\u00E1",
+ acirc: "\u00E2",
+ atilde: "\u00E3",
+ auml: "\u00E4",
+ aring: "\u00E5",
+ aelig: "\u00E6",
+ ccedil: "\u00E7",
+ egrave: "\u00E8",
+ eacute: "\u00E9",
+ ecirc: "\u00EA",
+ euml: "\u00EB",
+ igrave: "\u00EC",
+ iacute: "\u00ED",
+ icirc: "\u00EE",
+ iuml: "\u00EF",
+ eth: "\u00F0",
+ ntilde: "\u00F1",
+ ograve: "\u00F2",
+ oacute: "\u00F3",
+ ocirc: "\u00F4",
+ otilde: "\u00F5",
+ ouml: "\u00F6",
+ divide: "\u00F7",
+ oslash: "\u00F8",
+ ugrave: "\u00F9",
+ uacute: "\u00FA",
+ ucirc: "\u00FB",
+ uuml: "\u00FC",
+ yacute: "\u00FD",
+ thorn: "\u00FE",
+ yuml: "\u00FF",
+ OElig: "\u0152",
+ oelig: "\u0153",
+ Scaron: "\u0160",
+ scaron: "\u0161",
+ Yuml: "\u0178",
+ fnof: "\u0192",
+ circ: "\u02C6",
+ tilde: "\u02DC",
+ Alpha: "\u0391",
+ Beta: "\u0392",
+ Gamma: "\u0393",
+ Delta: "\u0394",
+ Epsilon: "\u0395",
+ Zeta: "\u0396",
+ Eta: "\u0397",
+ Theta: "\u0398",
+ Iota: "\u0399",
+ Kappa: "\u039A",
+ Lambda: "\u039B",
+ Mu: "\u039C",
+ Nu: "\u039D",
+ Xi: "\u039E",
+ Omicron: "\u039F",
+ Pi: "\u03A0",
+ Rho: "\u03A1",
+ Sigma: "\u03A3",
+ Tau: "\u03A4",
+ Upsilon: "\u03A5",
+ Phi: "\u03A6",
+ Chi: "\u03A7",
+ Psi: "\u03A8",
+ Omega: "\u03A9",
+ alpha: "\u03B1",
+ beta: "\u03B2",
+ gamma: "\u03B3",
+ delta: "\u03B4",
+ epsilon: "\u03B5",
+ zeta: "\u03B6",
+ eta: "\u03B7",
+ theta: "\u03B8",
+ iota: "\u03B9",
+ kappa: "\u03BA",
+ lambda: "\u03BB",
+ mu: "\u03BC",
+ nu: "\u03BD",
+ xi: "\u03BE",
+ omicron: "\u03BF",
+ pi: "\u03C0",
+ rho: "\u03C1",
+ sigmaf: "\u03C2",
+ sigma: "\u03C3",
+ tau: "\u03C4",
+ upsilon: "\u03C5",
+ phi: "\u03C6",
+ chi: "\u03C7",
+ psi: "\u03C8",
+ omega: "\u03C9",
+ thetasym: "\u03D1",
+ upsih: "\u03D2",
+ piv: "\u03D6",
+ ensp: "\u2002",
+ emsp: "\u2003",
+ thinsp: "\u2009",
+ zwnj: "\u200C",
+ zwj: "\u200D",
+ lrm: "\u200E",
+ rlm: "\u200F",
+ ndash: "\u2013",
+ mdash: "\u2014",
+ lsquo: "\u2018",
+ rsquo: "\u2019",
+ sbquo: "\u201A",
+ ldquo: "\u201C",
+ rdquo: "\u201D",
+ bdquo: "\u201E",
+ dagger: "\u2020",
+ Dagger: "\u2021",
+ bull: "\u2022",
+ hellip: "\u2026",
+ permil: "\u2030",
+ prime: "\u2032",
+ Prime: "\u2033",
+ lsaquo: "\u2039",
+ rsaquo: "\u203A",
+ oline: "\u203E",
+ frasl: "\u2044",
+ euro: "\u20AC",
+ image: "\u2111",
+ weierp: "\u2118",
+ real: "\u211C",
+ trade: "\u2122",
+ alefsym: "\u2135",
+ larr: "\u2190",
+ uarr: "\u2191",
+ rarr: "\u2192",
+ darr: "\u2193",
+ harr: "\u2194",
+ crarr: "\u21B5",
+ lArr: "\u21D0",
+ uArr: "\u21D1",
+ rArr: "\u21D2",
+ dArr: "\u21D3",
+ hArr: "\u21D4",
+ forall: "\u2200",
+ part: "\u2202",
+ exist: "\u2203",
+ empty: "\u2205",
+ nabla: "\u2207",
+ isin: "\u2208",
+ notin: "\u2209",
+ ni: "\u220B",
+ prod: "\u220F",
+ sum: "\u2211",
+ minus: "\u2212",
+ lowast: "\u2217",
+ radic: "\u221A",
+ prop: "\u221D",
+ infin: "\u221E",
+ ang: "\u2220",
+ and: "\u2227",
+ or: "\u2228",
+ cap: "\u2229",
+ cup: "\u222A",
+ "int": "\u222B",
+ there4: "\u2234",
+ sim: "\u223C",
+ cong: "\u2245",
+ asymp: "\u2248",
+ ne: "\u2260",
+ equiv: "\u2261",
+ le: "\u2264",
+ ge: "\u2265",
+ sub: "\u2282",
+ sup: "\u2283",
+ nsub: "\u2284",
+ sube: "\u2286",
+ supe: "\u2287",
+ oplus: "\u2295",
+ otimes: "\u2297",
+ perp: "\u22A5",
+ sdot: "\u22C5",
+ lceil: "\u2308",
+ rceil: "\u2309",
+ lfloor: "\u230A",
+ rfloor: "\u230B",
+ lang: "\u2329",
+ rang: "\u232A",
+ loz: "\u25CA",
+ spades: "\u2660",
+ clubs: "\u2663",
+ hearts: "\u2665",
+ diams: "\u2666"
+ };
+
+ function isXJSIdentifierStart(ch) {
+ // exclude backslash (\)
+ return (ch !== 92) && isIdentifierStart(ch);
+ }
+
+ function isXJSIdentifierPart(ch) {
+ // exclude backslash (\) and add hyphen (-)
+ return (ch !== 92) && (ch === 45 || isIdentifierPart(ch));
+ }
+
+ function scanXJSIdentifier() {
+ var ch, start, id = '', namespace;
+
+ start = index;
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (!isXJSIdentifierPart(ch)) {
+ break;
+ }
+ id += source[index++];
+ }
+
+ if (ch === 58) { // :
+ ++index;
+ namespace = id;
+ id = '';
+
+ while (index < length) {
+ ch = source.charCodeAt(index);
+ if (!isXJSIdentifierPart(ch)) {
+ break;
+ }
+ id += source[index++];
+ }
+ }
+
+ if (!id) {
+ throwError({}, Messages.InvalidXJSTagName);
+ }
+
+ return {
+ type: Token.XJSIdentifier,
+ value: id,
+ namespace: namespace,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanXJSEntity() {
+ var ch, str = '', count = 0, entity;
+ ch = source[index];
+ assert(ch === '&', 'Entity must start with an ampersand');
+ index++;
+ while (index < length && count++ < 10) {
+ ch = source[index++];
+ if (ch === ';') {
+ break;
+ }
+ str += ch;
+ }
+
+ if (str[0] === '#' && str[1] === 'x') {
+ entity = String.fromCharCode(parseInt(str.substr(2), 16));
+ } else if (str[0] === '#') {
+ entity = String.fromCharCode(parseInt(str.substr(1), 10));
+ } else {
+ entity = XHTMLEntities[str];
+ }
+ return entity;
+ }
+
+ function scanXJSText(stopChars) {
+ var ch, str = '', start;
+ start = index;
+ while (index < length) {
+ ch = source[index];
+ if (stopChars.indexOf(ch) !== -1) {
+ break;
+ }
+ if (ch === '&') {
+ str += scanXJSEntity();
+ } else {
+ ch = source[index++];
+ if (isLineTerminator(ch.charCodeAt(0))) {
+ ++lineNumber;
+ lineStart = index;
+ }
+ str += ch;
+ }
+ }
+ return {
+ type: Token.XJSText,
+ value: str,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanXJSStringLiteral() {
+ var innerToken, quote, start;
+
+ quote = source[index];
+ assert((quote === '\'' || quote === '"'),
+ 'String literal must starts with a quote');
+
+ start = index;
+ ++index;
+
+ innerToken = scanXJSText([quote]);
+
+ if (quote !== source[index]) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ ++index;
+
+ innerToken.range = [start, index];
+
+ return innerToken;
+ }
+
+ /**
+ * Between XJS opening and closing tags (e.g. HERE), anything that
+ * is not another XJS tag and is not an expression wrapped by {} is text.
+ */
+ function advanceXJSChild() {
+ var ch = source.charCodeAt(index);
+
+ // { (123) and < (60)
+ if (ch !== 123 && ch !== 60) {
+ return scanXJSText(['<', '{']);
+ }
+
+ return scanPunctuator();
+ }
+
+ function parseXJSIdentifier() {
+ var token;
+
+ if (lookahead.type !== Token.XJSIdentifier) {
+ throwUnexpected(lookahead);
+ }
+
+ token = lex();
+ return delegate.createXJSIdentifier(token.value, token.namespace);
+ }
+
+ function parseXJSAttributeValue() {
+ var value;
+ if (match('{')) {
+ value = parseXJSExpressionContainer();
+ if (value.expression.type === Syntax.XJSEmptyExpression) {
+ throwError(
+ value,
+ 'XJS attributes must only be assigned a non-empty ' +
+ 'expression'
+ );
+ }
+ } else if (match('<')) {
+ value = parseXJSElement();
+ } else if (lookahead.type === Token.XJSText) {
+ value = delegate.createLiteral(lex());
+ } else {
+ throwError({}, Messages.InvalidXJSAttributeValue);
+ }
+ return value;
+ }
+
+ function parseXJSEmptyExpression() {
+ while (source.charAt(index) !== '}') {
+ index++;
+ }
+ return delegate.createXJSEmptyExpression();
+ }
+
+ function parseXJSExpressionContainer() {
+ var expression, origInXJSChild, origInXJSTag;
+
+ origInXJSChild = state.inXJSChild;
+ origInXJSTag = state.inXJSTag;
+ state.inXJSChild = false;
+ state.inXJSTag = false;
+
+ expect('{');
+
+ if (match('}')) {
+ expression = parseXJSEmptyExpression();
+ } else {
+ expression = parseExpression();
+ }
+
+ state.inXJSChild = origInXJSChild;
+ state.inXJSTag = origInXJSTag;
+
+ expect('}');
+
+ return delegate.createXJSExpressionContainer(expression);
+ }
+
+ function parseXJSAttribute() {
+ var token, name, value;
+
+ name = parseXJSIdentifier();
+
+ // HTML empty attribute
+ if (match('=')) {
+ lex();
+ return delegate.createXJSAttribute(name, parseXJSAttributeValue());
+ }
+
+ return delegate.createXJSAttribute(name);
+ }
+
+ function parseXJSChild() {
+ var token;
+ if (match('{')) {
+ token = parseXJSExpressionContainer();
+ } else if (lookahead.type === Token.XJSText) {
+ token = delegate.createLiteral(lex());
+ } else {
+ token = parseXJSElement();
+ }
+ return token;
+ }
+
+ function parseXJSClosingElement() {
+ var name, origInXJSChild, origInXJSTag;
+ origInXJSChild = state.inXJSChild;
+ origInXJSTag = state.inXJSTag;
+ state.inXJSChild = false;
+ state.inXJSTag = true;
+ expect('<');
+ expect('/');
+ name = parseXJSIdentifier();
+ // Because advance() (called by lex() called by expect()) expects there
+ // to be a valid token after >, it needs to know whether to look for a
+ // standard JS token or an XJS text node
+ state.inXJSChild = origInXJSChild;
+ state.inXJSTag = origInXJSTag;
+ expect('>');
+ return delegate.createXJSClosingElement(name);
+ }
+
+ function parseXJSOpeningElement() {
+ var name, attribute, attributes = [], selfClosing = false, origInXJSChild, origInXJSTag;
+
+ origInXJSChild = state.inXJSChild;
+ origInXJSTag = state.inXJSTag;
+ state.inXJSChild = false;
+ state.inXJSTag = true;
+
+ expect('<');
+
+ name = parseXJSIdentifier();
+
+ while (index < length &&
+ lookahead.value !== '/' &&
+ lookahead.value !== '>') {
+ attributes.push(parseXJSAttribute());
+ }
+
+ state.inXJSTag = origInXJSTag;
+
+ if (lookahead.value === '/') {
+ expect('/');
+ // Because advance() (called by lex() called by expect()) expects
+ // there to be a valid token after >, it needs to know whether to
+ // look for a standard JS token or an XJS text node
+ state.inXJSChild = origInXJSChild;
+ expect('>');
+ selfClosing = true;
+ } else {
+ state.inXJSChild = true;
+ expect('>');
+ }
+ return delegate.createXJSOpeningElement(name, attributes, selfClosing);
+ }
+
+ function parseXJSElement() {
+ var openingElement, closingElement, children = [], origInXJSChild, origInXJSTag;
+
+ origInXJSChild = state.inXJSChild;
+ origInXJSTag = state.inXJSTag;
+ openingElement = parseXJSOpeningElement();
+
+ if (!openingElement.selfClosing) {
+ while (index < length) {
+ state.inXJSChild = false; // Call lookahead2() with inXJSChild = false because should not be considered in the child
+ if (lookahead.value === '<' && lookahead2().value === '/') {
+ break;
+ }
+ state.inXJSChild = true;
+ peek(); // reset lookahead token
+ children.push(parseXJSChild());
+ }
+ state.inXJSChild = origInXJSChild;
+ state.inXJSTag = origInXJSTag;
+ closingElement = parseXJSClosingElement();
+ if (closingElement.name.namespace !== openingElement.name.namespace || closingElement.name.name !== openingElement.name.name) {
+ throwError({}, Messages.ExpectedXJSClosingTag, openingElement.name.namespace ? openingElement.name.namespace + ':' + openingElement.name.name : openingElement.name.name);
+ }
+ }
+
+ return delegate.createXJSElement(openingElement, closingElement, children);
+ }
+
+ function collectToken() {
+ var start, loc, token, range, value;
+
+ skipComment();
+ start = index;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+
+ token = extra.advance();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ if (token.type !== Token.EOF) {
+ range = [token.range[0], token.range[1]];
+ value = source.slice(token.range[0], token.range[1]);
+ extra.tokens.push({
+ type: TokenName[token.type],
+ value: value,
+ range: range,
+ loc: loc
+ });
+ }
+
+ return token;
+ }
+
+ function collectRegex() {
+ var pos, loc, regex, token;
+
+ skipComment();
+
+ pos = index;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+
+ regex = extra.scanRegExp();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ if (!extra.tokenize) {
+ // Pop the previous token, which is likely '/' or '/='
+ if (extra.tokens.length > 0) {
+ token = extra.tokens[extra.tokens.length - 1];
+ if (token.range[0] === pos && token.type === 'Punctuator') {
+ if (token.value === '/' || token.value === '/=') {
+ extra.tokens.pop();
+ }
+ }
+ }
+
+ extra.tokens.push({
+ type: 'RegularExpression',
+ value: regex.literal,
+ range: [pos, index],
+ loc: loc
+ });
+ }
+
+ return regex;
+ }
+
+ function filterTokenLocation() {
+ var i, entry, token, tokens = [];
+
+ for (i = 0; i < extra.tokens.length; ++i) {
+ entry = extra.tokens[i];
+ token = {
+ type: entry.type,
+ value: entry.value
+ };
+ if (extra.range) {
+ token.range = entry.range;
+ }
+ if (extra.loc) {
+ token.loc = entry.loc;
+ }
+ tokens.push(token);
+ }
+
+ extra.tokens = tokens;
+ }
+
+ function LocationMarker() {
+ this.range = [index, index];
+ this.loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ },
+ end: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+ }
+
+ LocationMarker.prototype = {
+ constructor: LocationMarker,
+
+ end: function () {
+ this.range[1] = index;
+ this.loc.end.line = lineNumber;
+ this.loc.end.column = index - lineStart;
+ },
+
+ applyGroup: function (node) {
+ if (extra.range) {
+ node.groupRange = [this.range[0], this.range[1]];
+ }
+ if (extra.loc) {
+ node.groupLoc = {
+ start: {
+ line: this.loc.start.line,
+ column: this.loc.start.column
+ },
+ end: {
+ line: this.loc.end.line,
+ column: this.loc.end.column
+ }
+ };
+ node = delegate.postProcess(node);
+ }
+ },
+
+ apply: function (node) {
+ var nodeType = typeof node;
+ assert(nodeType === 'object',
+ 'Applying location marker to an unexpected node type: ' +
+ nodeType);
+
+ if (extra.range) {
+ node.range = [this.range[0], this.range[1]];
+ }
+ if (extra.loc) {
+ node.loc = {
+ start: {
+ line: this.loc.start.line,
+ column: this.loc.start.column
+ },
+ end: {
+ line: this.loc.end.line,
+ column: this.loc.end.column
+ }
+ };
+ node = delegate.postProcess(node);
+ }
+ }
+ };
+
+ function createLocationMarker() {
+ return new LocationMarker();
+ }
+
+ function trackGroupExpression() {
+ var marker, expr;
+
+ skipComment();
+ marker = createLocationMarker();
+ expect('(');
+
+ ++state.parenthesizedCount;
+ expr = parseExpression();
+
+ expect(')');
+ marker.end();
+ marker.applyGroup(expr);
+
+ return expr;
+ }
+
+ function trackLeftHandSideExpression() {
+ var marker, expr;
+
+ skipComment();
+ marker = createLocationMarker();
+
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+
+ while (match('.') || match('[') || lookahead.type === Token.Template) {
+ if (match('[')) {
+ expr = delegate.createMemberExpression('[', expr, parseComputedMember());
+ marker.end();
+ marker.apply(expr);
+ } else if (match('.')) {
+ expr = delegate.createMemberExpression('.', expr, parseNonComputedMember());
+ marker.end();
+ marker.apply(expr);
+ } else {
+ expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral());
+ marker.end();
+ marker.apply(expr);
+ }
+ }
+
+ return expr;
+ }
+
+ function trackLeftHandSideExpressionAllowCall() {
+ var marker, expr, args;
+
+ skipComment();
+ marker = createLocationMarker();
+
+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
+
+ while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) {
+ if (match('(')) {
+ args = parseArguments();
+ expr = delegate.createCallExpression(expr, args);
+ marker.end();
+ marker.apply(expr);
+ } else if (match('[')) {
+ expr = delegate.createMemberExpression('[', expr, parseComputedMember());
+ marker.end();
+ marker.apply(expr);
+ } else if (match('.')) {
+ expr = delegate.createMemberExpression('.', expr, parseNonComputedMember());
+ marker.end();
+ marker.apply(expr);
+ } else {
+ expr = delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral());
+ marker.end();
+ marker.apply(expr);
+ }
+ }
+
+ return expr;
+ }
+
+ function filterGroup(node) {
+ var n, i, entry;
+
+ n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
+ for (i in node) {
+ if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
+ entry = node[i];
+ if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
+ n[i] = entry;
+ } else {
+ n[i] = filterGroup(entry);
+ }
+ }
+ }
+ return n;
+ }
+
+ function wrapTrackingFunction(range, loc, preserveWhitespace) {
+
+ return function (parseFunction) {
+
+ function isBinary(node) {
+ return node.type === Syntax.LogicalExpression ||
+ node.type === Syntax.BinaryExpression;
+ }
+
+ function visit(node) {
+ var start, end;
+
+ if (isBinary(node.left)) {
+ visit(node.left);
+ }
+ if (isBinary(node.right)) {
+ visit(node.right);
+ }
+
+ if (range) {
+ if (node.left.groupRange || node.right.groupRange) {
+ start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
+ end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
+ node.range = [start, end];
+ } else if (typeof node.range === 'undefined') {
+ start = node.left.range[0];
+ end = node.right.range[1];
+ node.range = [start, end];
+ }
+ }
+ if (loc) {
+ if (node.left.groupLoc || node.right.groupLoc) {
+ start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
+ end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
+ node.loc = {
+ start: start,
+ end: end
+ };
+ node = delegate.postProcess(node);
+ } else if (typeof node.loc === 'undefined') {
+ node.loc = {
+ start: node.left.loc.start,
+ end: node.right.loc.end
+ };
+ node = delegate.postProcess(node);
+ }
+ }
+ }
+
+ return function () {
+ var marker, node;
+
+ if (!preserveWhitespace) {
+ skipComment();
+ }
+
+ marker = createLocationMarker();
+ node = parseFunction.apply(null, arguments);
+ marker.end();
+
+ if (range && typeof node.range === 'undefined') {
+ marker.apply(node);
+ }
+
+ if (loc && typeof node.loc === 'undefined') {
+ marker.apply(node);
+ }
+
+ if (isBinary(node)) {
+ visit(node);
+ }
+
+ return node;
+ };
+ };
+ }
+
+ function patch() {
+
+ var wrapTracking, wrapTrackingPreserveWhitespace;
+
+ if (extra.comments) {
+ extra.skipComment = skipComment;
+ skipComment = scanComment;
+ }
+
+ if (extra.range || extra.loc) {
+
+ extra.parseGroupExpression = parseGroupExpression;
+ extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
+ extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
+ parseGroupExpression = trackGroupExpression;
+ parseLeftHandSideExpression = trackLeftHandSideExpression;
+ parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
+
+ wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
+ wrapTrackingPreserveWhitespace =
+ wrapTrackingFunction(extra.range, extra.loc, true);
+
+ extra.parseArrayInitialiser = parseArrayInitialiser;
+ extra.parseAssignmentExpression = parseAssignmentExpression;
+ extra.parseBinaryExpression = parseBinaryExpression;
+ extra.parseBlock = parseBlock;
+ extra.parseFunctionSourceElements = parseFunctionSourceElements;
+ extra.parseCatchClause = parseCatchClause;
+ extra.parseComputedMember = parseComputedMember;
+ extra.parseConditionalExpression = parseConditionalExpression;
+ extra.parseConstLetDeclaration = parseConstLetDeclaration;
+ extra.parseExportBatchSpecifier = parseExportBatchSpecifier;
+ extra.parseExportDeclaration = parseExportDeclaration;
+ extra.parseExportSpecifier = parseExportSpecifier;
+ extra.parseExpression = parseExpression;
+ extra.parseForVariableDeclaration = parseForVariableDeclaration;
+ extra.parseFunctionDeclaration = parseFunctionDeclaration;
+ extra.parseFunctionExpression = parseFunctionExpression;
+ extra.parseParams = parseParams;
+ extra.parseImportDeclaration = parseImportDeclaration;
+ extra.parseImportSpecifier = parseImportSpecifier;
+ extra.parseModuleDeclaration = parseModuleDeclaration;
+ extra.parseModuleBlock = parseModuleBlock;
+ extra.parseNewExpression = parseNewExpression;
+ extra.parseNonComputedProperty = parseNonComputedProperty;
+ extra.parseObjectInitialiser = parseObjectInitialiser;
+ extra.parseObjectProperty = parseObjectProperty;
+ extra.parseObjectPropertyKey = parseObjectPropertyKey;
+ extra.parsePostfixExpression = parsePostfixExpression;
+ extra.parsePrimaryExpression = parsePrimaryExpression;
+ extra.parseProgram = parseProgram;
+ extra.parsePropertyFunction = parsePropertyFunction;
+ extra.parseSpreadOrAssignmentExpression = parseSpreadOrAssignmentExpression;
+ extra.parseTemplateElement = parseTemplateElement;
+ extra.parseTemplateLiteral = parseTemplateLiteral;
+ extra.parseTypeAnnotatableIdentifier = parseTypeAnnotatableIdentifier;
+ extra.parseTypeAnnotation = parseTypeAnnotation;
+ extra.parseStatement = parseStatement;
+ extra.parseSwitchCase = parseSwitchCase;
+ extra.parseUnaryExpression = parseUnaryExpression;
+ extra.parseVariableDeclaration = parseVariableDeclaration;
+ extra.parseVariableIdentifier = parseVariableIdentifier;
+ extra.parseMethodDefinition = parseMethodDefinition;
+ extra.parseClassDeclaration = parseClassDeclaration;
+ extra.parseClassExpression = parseClassExpression;
+ extra.parseClassBody = parseClassBody;
+ extra.parseXJSIdentifier = parseXJSIdentifier;
+ extra.parseXJSChild = parseXJSChild;
+ extra.parseXJSAttribute = parseXJSAttribute;
+ extra.parseXJSAttributeValue = parseXJSAttributeValue;
+ extra.parseXJSExpressionContainer = parseXJSExpressionContainer;
+ extra.parseXJSEmptyExpression = parseXJSEmptyExpression;
+ extra.parseXJSElement = parseXJSElement;
+ extra.parseXJSClosingElement = parseXJSClosingElement;
+ extra.parseXJSOpeningElement = parseXJSOpeningElement;
+
+ parseArrayInitialiser = wrapTracking(extra.parseArrayInitialiser);
+ parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
+ parseBinaryExpression = wrapTracking(extra.parseBinaryExpression);
+ parseBlock = wrapTracking(extra.parseBlock);
+ parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
+ parseCatchClause = wrapTracking(extra.parseCatchClause);
+ parseComputedMember = wrapTracking(extra.parseComputedMember);
+ parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
+ parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
+ parseExportBatchSpecifier = wrapTracking(parseExportBatchSpecifier);
+ parseExportDeclaration = wrapTracking(parseExportDeclaration);
+ parseExportSpecifier = wrapTracking(parseExportSpecifier);
+ parseExpression = wrapTracking(extra.parseExpression);
+ parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
+ parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
+ parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
+ parseParams = wrapTracking(extra.parseParams);
+ parseImportDeclaration = wrapTracking(extra.parseImportDeclaration);
+ parseImportSpecifier = wrapTracking(extra.parseImportSpecifier);
+ parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration);
+ parseModuleBlock = wrapTracking(extra.parseModuleBlock);
+ parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
+ parseNewExpression = wrapTracking(extra.parseNewExpression);
+ parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
+ parseObjectInitialiser = wrapTracking(extra.parseObjectInitialiser);
+ parseObjectProperty = wrapTracking(extra.parseObjectProperty);
+ parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
+ parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
+ parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
+ parseProgram = wrapTracking(extra.parseProgram);
+ parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
+ parseTemplateElement = wrapTracking(extra.parseTemplateElement);
+ parseTemplateLiteral = wrapTracking(extra.parseTemplateLiteral);
+ parseTypeAnnotatableIdentifier = wrapTracking(extra.parseTypeAnnotatableIdentifier);
+ parseTypeAnnotation = wrapTracking(extra.parseTypeAnnotation);
+ parseSpreadOrAssignmentExpression = wrapTracking(extra.parseSpreadOrAssignmentExpression);
+ parseStatement = wrapTracking(extra.parseStatement);
+ parseSwitchCase = wrapTracking(extra.parseSwitchCase);
+ parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
+ parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
+ parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
+ parseMethodDefinition = wrapTracking(extra.parseMethodDefinition);
+ parseClassDeclaration = wrapTracking(extra.parseClassDeclaration);
+ parseClassExpression = wrapTracking(extra.parseClassExpression);
+ parseClassBody = wrapTracking(extra.parseClassBody);
+ parseXJSIdentifier = wrapTracking(extra.parseXJSIdentifier);
+ parseXJSChild = wrapTrackingPreserveWhitespace(extra.parseXJSChild);
+ parseXJSAttribute = wrapTracking(extra.parseXJSAttribute);
+ parseXJSAttributeValue = wrapTracking(extra.parseXJSAttributeValue);
+ parseXJSExpressionContainer = wrapTracking(extra.parseXJSExpressionContainer);
+ parseXJSEmptyExpression = wrapTrackingPreserveWhitespace(extra.parseXJSEmptyExpression);
+ parseXJSElement = wrapTracking(extra.parseXJSElement);
+ parseXJSClosingElement = wrapTracking(extra.parseXJSClosingElement);
+ parseXJSOpeningElement = wrapTracking(extra.parseXJSOpeningElement);
+ }
+
+ if (typeof extra.tokens !== 'undefined') {
+ extra.advance = advance;
+ extra.scanRegExp = scanRegExp;
+
+ advance = collectToken;
+ scanRegExp = collectRegex;
+ }
+ }
+
+ function unpatch() {
+ if (typeof extra.skipComment === 'function') {
+ skipComment = extra.skipComment;
+ }
+
+ if (extra.range || extra.loc) {
+ parseArrayInitialiser = extra.parseArrayInitialiser;
+ parseAssignmentExpression = extra.parseAssignmentExpression;
+ parseBinaryExpression = extra.parseBinaryExpression;
+ parseBlock = extra.parseBlock;
+ parseFunctionSourceElements = extra.parseFunctionSourceElements;
+ parseCatchClause = extra.parseCatchClause;
+ parseComputedMember = extra.parseComputedMember;
+ parseConditionalExpression = extra.parseConditionalExpression;
+ parseConstLetDeclaration = extra.parseConstLetDeclaration;
+ parseExportBatchSpecifier = extra.parseExportBatchSpecifier;
+ parseExportDeclaration = extra.parseExportDeclaration;
+ parseExportSpecifier = extra.parseExportSpecifier;
+ parseExpression = extra.parseExpression;
+ parseForVariableDeclaration = extra.parseForVariableDeclaration;
+ parseFunctionDeclaration = extra.parseFunctionDeclaration;
+ parseFunctionExpression = extra.parseFunctionExpression;
+ parseImportDeclaration = extra.parseImportDeclaration;
+ parseImportSpecifier = extra.parseImportSpecifier;
+ parseGroupExpression = extra.parseGroupExpression;
+ parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
+ parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
+ parseModuleDeclaration = extra.parseModuleDeclaration;
+ parseModuleBlock = extra.parseModuleBlock;
+ parseNewExpression = extra.parseNewExpression;
+ parseNonComputedProperty = extra.parseNonComputedProperty;
+ parseObjectInitialiser = extra.parseObjectInitialiser;
+ parseObjectProperty = extra.parseObjectProperty;
+ parseObjectPropertyKey = extra.parseObjectPropertyKey;
+ parsePostfixExpression = extra.parsePostfixExpression;
+ parsePrimaryExpression = extra.parsePrimaryExpression;
+ parseProgram = extra.parseProgram;
+ parsePropertyFunction = extra.parsePropertyFunction;
+ parseTemplateElement = extra.parseTemplateElement;
+ parseTemplateLiteral = extra.parseTemplateLiteral;
+ parseTypeAnnotatableIdentifier = extra.parseTypeAnnotatableIdentifier;
+ parseTypeAnnotation = extra.parseTypeAnnotation;
+ parseSpreadOrAssignmentExpression = extra.parseSpreadOrAssignmentExpression;
+ parseStatement = extra.parseStatement;
+ parseSwitchCase = extra.parseSwitchCase;
+ parseUnaryExpression = extra.parseUnaryExpression;
+ parseVariableDeclaration = extra.parseVariableDeclaration;
+ parseVariableIdentifier = extra.parseVariableIdentifier;
+ parseMethodDefinition = extra.parseMethodDefinition;
+ parseClassDeclaration = extra.parseClassDeclaration;
+ parseClassExpression = extra.parseClassExpression;
+ parseClassBody = extra.parseClassBody;
+ parseXJSIdentifier = extra.parseXJSIdentifier;
+ parseXJSChild = extra.parseXJSChild;
+ parseXJSAttribute = extra.parseXJSAttribute;
+ parseXJSAttributeValue = extra.parseXJSAttributeValue;
+ parseXJSExpressionContainer = extra.parseXJSExpressionContainer;
+ parseXJSEmptyExpression = extra.parseXJSEmptyExpression;
+ parseXJSElement = extra.parseXJSElement;
+ parseXJSClosingElement = extra.parseXJSClosingElement;
+ parseXJSOpeningElement = extra.parseXJSOpeningElement;
+ }
+
+ if (typeof extra.scanRegExp === 'function') {
+ advance = extra.advance;
+ scanRegExp = extra.scanRegExp;
+ }
+ }
+
+ // This is used to modify the delegate.
+
+ function extend(object, properties) {
+ var entry, result = {};
+
+ for (entry in object) {
+ if (object.hasOwnProperty(entry)) {
+ result[entry] = object[entry];
+ }
+ }
+
+ for (entry in properties) {
+ if (properties.hasOwnProperty(entry)) {
+ result[entry] = properties[entry];
+ }
+ }
+
+ return result;
+ }
+
+ function tokenize(code, options) {
+ var toString,
+ token,
+ tokens;
+
+ toString = String;
+ if (typeof code !== 'string' && !(code instanceof String)) {
+ code = toString(code);
+ }
+
+ delegate = SyntaxTreeDelegate;
+ source = code;
+ index = 0;
+ lineNumber = (source.length > 0) ? 1 : 0;
+ lineStart = 0;
+ length = source.length;
+ lookahead = null;
+ state = {
+ allowKeyword: true,
+ allowIn: true,
+ labelSet: {},
+ inFunctionBody: false,
+ inIteration: false,
+ inSwitch: false
+ };
+
+ extra = {};
+
+ // Options matching.
+ options = options || {};
+
+ // Of course we collect tokens here.
+ options.tokens = true;
+ extra.tokens = [];
+ extra.tokenize = true;
+ // The following two fields are necessary to compute the Regex tokens.
+ extra.openParenToken = -1;
+ extra.openCurlyToken = -1;
+
+ extra.range = (typeof options.range === 'boolean') && options.range;
+ extra.loc = (typeof options.loc === 'boolean') && options.loc;
+
+ if (typeof options.comment === 'boolean' && options.comment) {
+ extra.comments = [];
+ }
+ if (typeof options.tolerant === 'boolean' && options.tolerant) {
+ extra.errors = [];
+ }
+
+ if (length > 0) {
+ if (typeof source[0] === 'undefined') {
+ // Try first to convert to a string. This is good as fast path
+ // for old IE which understands string indexing for string
+ // literals only and not for string object.
+ if (code instanceof String) {
+ source = code.valueOf();
+ }
+ }
+ }
+
+ patch();
+
+ try {
+ peek();
+ if (lookahead.type === Token.EOF) {
+ return extra.tokens;
+ }
+
+ token = lex();
+ while (lookahead.type !== Token.EOF) {
+ try {
+ token = lex();
+ } catch (lexError) {
+ token = lookahead;
+ if (extra.errors) {
+ extra.errors.push(lexError);
+ // We have to break on the first error
+ // to avoid infinite loops.
+ break;
+ } else {
+ throw lexError;
+ }
+ }
+ }
+
+ filterTokenLocation();
+ tokens = extra.tokens;
+ if (typeof extra.comments !== 'undefined') {
+ filterCommentLocation();
+ tokens.comments = extra.comments;
+ }
+ if (typeof extra.errors !== 'undefined') {
+ tokens.errors = extra.errors;
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ unpatch();
+ extra = {};
+ }
+ return tokens;
+ }
+
+ function parse(code, options) {
+ var program, toString;
+
+ toString = String;
+ if (typeof code !== 'string' && !(code instanceof String)) {
+ code = toString(code);
+ }
+
+ delegate = SyntaxTreeDelegate;
+ source = code;
+ index = 0;
+ lineNumber = (source.length > 0) ? 1 : 0;
+ lineStart = 0;
+ length = source.length;
+ lookahead = null;
+ state = {
+ allowKeyword: false,
+ allowIn: true,
+ labelSet: {},
+ parenthesizedCount: 0,
+ inFunctionBody: false,
+ inIteration: false,
+ inSwitch: false,
+ inXJSChild: false,
+ inXJSTag: false,
+ yieldAllowed: false,
+ yieldFound: false
+ };
+
+ extra = {};
+ if (typeof options !== 'undefined') {
+ extra.range = (typeof options.range === 'boolean') && options.range;
+ extra.loc = (typeof options.loc === 'boolean') && options.loc;
+
+ if (extra.loc && options.source !== null && options.source !== undefined) {
+ delegate = extend(delegate, {
+ 'postProcess': function (node) {
+ node.loc.source = toString(options.source);
+ return node;
+ }
+ });
+ }
+
+ if (typeof options.tokens === 'boolean' && options.tokens) {
+ extra.tokens = [];
+ }
+ if (typeof options.comment === 'boolean' && options.comment) {
+ extra.comments = [];
+ }
+ if (typeof options.tolerant === 'boolean' && options.tolerant) {
+ extra.errors = [];
+ }
+ }
+
+ if (length > 0) {
+ if (typeof source[0] === 'undefined') {
+ // Try first to convert to a string. This is good as fast path
+ // for old IE which understands string indexing for string
+ // literals only and not for string object.
+ if (code instanceof String) {
+ source = code.valueOf();
+ }
+ }
+ }
+
+ patch();
+ try {
+ program = parseProgram();
+ if (typeof extra.comments !== 'undefined') {
+ filterCommentLocation();
+ program.comments = extra.comments;
+ }
+ if (typeof extra.tokens !== 'undefined') {
+ filterTokenLocation();
+ program.tokens = extra.tokens;
+ }
+ if (typeof extra.errors !== 'undefined') {
+ program.errors = extra.errors;
+ }
+ if (extra.range || extra.loc) {
+ program.body = filterGroup(program.body);
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ unpatch();
+ extra = {};
+ }
+
+ return program;
+ }
+
+ // Sync with *.json manifests.
+ exports.version = '1.1.0-dev-harmony';
+
+ exports.tokenize = tokenize;
+
+ exports.parse = parse;
+
+ // Deep copy.
+ exports.Syntax = (function () {
+ var name, types = {};
+
+ if (typeof Object.create === 'function') {
+ types = Object.create(null);
+ }
+
+ for (name in Syntax) {
+ if (Syntax.hasOwnProperty(name)) {
+ types[name] = Syntax[name];
+ }
+ }
+
+ if (typeof Object.freeze === 'function') {
+ Object.freeze(types);
+ }
+
+ return types;
+ }());
+
+}));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+},{}],7:[function(require,module,exports){
+var Base62 = (function (my) {
+ my.chars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
+
+ my.encode = function(i){
+ if (i === 0) {return '0'}
+ var s = ''
+ while (i > 0) {
+ s = this.chars[i % 62] + s
+ i = Math.floor(i/62)
+ }
+ return s
+ };
+ my.decode = function(a,b,c,d){
+ for (
+ b = c = (
+ a === (/\W|_|^$/.test(a += "") || a)
+ ) - 1;
+ d = a.charCodeAt(c++);
+ )
+ b = b * 62 + d - [, 48, 29, 87][d >> 5];
+ return b
+ };
+
+ return my;
+}({}));
+
+module.exports = Base62
+},{}],8:[function(require,module,exports){
+/*
+ * Copyright 2009-2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE.txt or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator;
+exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer;
+exports.SourceNode = require('./source-map/source-node').SourceNode;
+
+},{"./source-map/source-map-consumer":13,"./source-map/source-map-generator":14,"./source-map/source-node":15}],9:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var util = require('./util');
+
+ /**
+ * A data structure which is a combination of an array and a set. Adding a new
+ * member is O(1), testing for membership is O(1), and finding the index of an
+ * element is O(1). Removing elements from the set is not supported. Only
+ * strings are supported for membership.
+ */
+ function ArraySet() {
+ this._array = [];
+ this._set = {};
+ }
+
+ /**
+ * Static method for creating ArraySet instances from an existing array.
+ */
+ ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) {
+ var set = new ArraySet();
+ for (var i = 0, len = aArray.length; i < len; i++) {
+ set.add(aArray[i], aAllowDuplicates);
+ }
+ return set;
+ };
+
+ /**
+ * Add the given string to this set.
+ *
+ * @param String aStr
+ */
+ ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) {
+ var isDuplicate = this.has(aStr);
+ var idx = this._array.length;
+ if (!isDuplicate || aAllowDuplicates) {
+ this._array.push(aStr);
+ }
+ if (!isDuplicate) {
+ this._set[util.toSetString(aStr)] = idx;
+ }
+ };
+
+ /**
+ * Is the given string a member of this set?
+ *
+ * @param String aStr
+ */
+ ArraySet.prototype.has = function ArraySet_has(aStr) {
+ return Object.prototype.hasOwnProperty.call(this._set,
+ util.toSetString(aStr));
+ };
+
+ /**
+ * What is the index of the given string in the array?
+ *
+ * @param String aStr
+ */
+ ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
+ if (this.has(aStr)) {
+ return this._set[util.toSetString(aStr)];
+ }
+ throw new Error('"' + aStr + '" is not in the set.');
+ };
+
+ /**
+ * What is the element at the given index?
+ *
+ * @param Number aIdx
+ */
+ ArraySet.prototype.at = function ArraySet_at(aIdx) {
+ if (aIdx >= 0 && aIdx < this._array.length) {
+ return this._array[aIdx];
+ }
+ throw new Error('No element indexed by ' + aIdx);
+ };
+
+ /**
+ * Returns the array representation of this set (which has the proper indices
+ * indicated by indexOf). Note that this is a copy of the internal array used
+ * for storing the members so that no one can mess with internal state.
+ */
+ ArraySet.prototype.toArray = function ArraySet_toArray() {
+ return this._array.slice();
+ };
+
+ exports.ArraySet = ArraySet;
+
+});
+
+},{"./util":16,"amdefine":17}],10:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ *
+ * Based on the Base 64 VLQ implementation in Closure Compiler:
+ * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
+ *
+ * Copyright 2011 The Closure Compiler Authors. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var base64 = require('./base64');
+
+ // A single base 64 digit can contain 6 bits of data. For the base 64 variable
+ // length quantities we use in the source map spec, the first bit is the sign,
+ // the next four bits are the actual value, and the 6th bit is the
+ // continuation bit. The continuation bit tells us whether there are more
+ // digits in this value following this digit.
+ //
+ // Continuation
+ // | Sign
+ // | |
+ // V V
+ // 101011
+
+ var VLQ_BASE_SHIFT = 5;
+
+ // binary: 100000
+ var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
+
+ // binary: 011111
+ var VLQ_BASE_MASK = VLQ_BASE - 1;
+
+ // binary: 100000
+ var VLQ_CONTINUATION_BIT = VLQ_BASE;
+
+ /**
+ * Converts from a two-complement value to a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
+ * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
+ */
+ function toVLQSigned(aValue) {
+ return aValue < 0
+ ? ((-aValue) << 1) + 1
+ : (aValue << 1) + 0;
+ }
+
+ /**
+ * Converts to a two-complement value from a value where the sign bit is
+ * is placed in the least significant bit. For example, as decimals:
+ * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
+ * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
+ */
+ function fromVLQSigned(aValue) {
+ var isNegative = (aValue & 1) === 1;
+ var shifted = aValue >> 1;
+ return isNegative
+ ? -shifted
+ : shifted;
+ }
+
+ /**
+ * Returns the base 64 VLQ encoded value.
+ */
+ exports.encode = function base64VLQ_encode(aValue) {
+ var encoded = "";
+ var digit;
+
+ var vlq = toVLQSigned(aValue);
+
+ do {
+ digit = vlq & VLQ_BASE_MASK;
+ vlq >>>= VLQ_BASE_SHIFT;
+ if (vlq > 0) {
+ // There are still more digits in this value, so we must make sure the
+ // continuation bit is marked.
+ digit |= VLQ_CONTINUATION_BIT;
+ }
+ encoded += base64.encode(digit);
+ } while (vlq > 0);
+
+ return encoded;
+ };
+
+ /**
+ * Decodes the next base 64 VLQ value from the given string and returns the
+ * value and the rest of the string.
+ */
+ exports.decode = function base64VLQ_decode(aStr) {
+ var i = 0;
+ var strLen = aStr.length;
+ var result = 0;
+ var shift = 0;
+ var continuation, digit;
+
+ do {
+ if (i >= strLen) {
+ throw new Error("Expected more digits in base 64 VLQ value.");
+ }
+ digit = base64.decode(aStr.charAt(i++));
+ continuation = !!(digit & VLQ_CONTINUATION_BIT);
+ digit &= VLQ_BASE_MASK;
+ result = result + (digit << shift);
+ shift += VLQ_BASE_SHIFT;
+ } while (continuation);
+
+ return {
+ value: fromVLQSigned(result),
+ rest: aStr.slice(i)
+ };
+ };
+
+});
+
+},{"./base64":11,"amdefine":17}],11:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var charToIntMap = {};
+ var intToCharMap = {};
+
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+ .split('')
+ .forEach(function (ch, index) {
+ charToIntMap[ch] = index;
+ intToCharMap[index] = ch;
+ });
+
+ /**
+ * Encode an integer in the range of 0 to 63 to a single base 64 digit.
+ */
+ exports.encode = function base64_encode(aNumber) {
+ if (aNumber in intToCharMap) {
+ return intToCharMap[aNumber];
+ }
+ throw new TypeError("Must be between 0 and 63: " + aNumber);
+ };
+
+ /**
+ * Decode a single base 64 digit to an integer.
+ */
+ exports.decode = function base64_decode(aChar) {
+ if (aChar in charToIntMap) {
+ return charToIntMap[aChar];
+ }
+ throw new TypeError("Not a valid base 64 digit: " + aChar);
+ };
+
+});
+
+},{"amdefine":17}],12:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ /**
+ * Recursive implementation of binary search.
+ *
+ * @param aLow Indices here and lower do not contain the needle.
+ * @param aHigh Indices here and higher do not contain the needle.
+ * @param aNeedle The element being searched for.
+ * @param aHaystack The non-empty array being searched.
+ * @param aCompare Function which takes two elements and returns -1, 0, or 1.
+ */
+ function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) {
+ // This function terminates when one of the following is true:
+ //
+ // 1. We find the exact element we are looking for.
+ //
+ // 2. We did not find the exact element, but we can return the next
+ // closest element that is less than that element.
+ //
+ // 3. We did not find the exact element, and there is no next-closest
+ // element which is less than the one we are searching for, so we
+ // return null.
+ var mid = Math.floor((aHigh - aLow) / 2) + aLow;
+ var cmp = aCompare(aNeedle, aHaystack[mid], true);
+ if (cmp === 0) {
+ // Found the element we are looking for.
+ return aHaystack[mid];
+ }
+ else if (cmp > 0) {
+ // aHaystack[mid] is greater than our needle.
+ if (aHigh - mid > 1) {
+ // The element is in the upper half.
+ return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare);
+ }
+ // We did not find an exact match, return the next closest one
+ // (termination case 2).
+ return aHaystack[mid];
+ }
+ else {
+ // aHaystack[mid] is less than our needle.
+ if (mid - aLow > 1) {
+ // The element is in the lower half.
+ return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare);
+ }
+ // The exact needle element was not found in this haystack. Determine if
+ // we are in termination case (2) or (3) and return the appropriate thing.
+ return aLow < 0
+ ? null
+ : aHaystack[aLow];
+ }
+ }
+
+ /**
+ * This is an implementation of binary search which will always try and return
+ * the next lowest value checked if there is no exact hit. This is because
+ * mappings between original and generated line/col pairs are single points,
+ * and there is an implicit region between each of them, so a miss just means
+ * that you aren't on the very start of a region.
+ *
+ * @param aNeedle The element you are looking for.
+ * @param aHaystack The array that is being searched.
+ * @param aCompare A function which takes the needle and an element in the
+ * array and returns -1, 0, or 1 depending on whether the needle is less
+ * than, equal to, or greater than the element, respectively.
+ */
+ exports.search = function search(aNeedle, aHaystack, aCompare) {
+ return aHaystack.length > 0
+ ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
+ : null;
+ };
+
+});
+
+},{"amdefine":17}],13:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var util = require('./util');
+ var binarySearch = require('./binary-search');
+ var ArraySet = require('./array-set').ArraySet;
+ var base64VLQ = require('./base64-vlq');
+
+ /**
+ * A SourceMapConsumer instance represents a parsed source map which we can
+ * query for information about the original file positions by giving it a file
+ * position in the generated source.
+ *
+ * The only parameter is the raw source map (either as a JSON string, or
+ * already parsed to an object). According to the spec, source maps have the
+ * following attributes:
+ *
+ * - version: Which version of the source map spec this map is following.
+ * - sources: An array of URLs to the original source files.
+ * - names: An array of identifiers which can be referrenced by individual mappings.
+ * - sourceRoot: Optional. The URL root from which all sources are relative.
+ * - sourcesContent: Optional. An array of contents of the original source files.
+ * - mappings: A string of base64 VLQs which contain the actual mappings.
+ * - file: The generated file this source map is associated with.
+ *
+ * Here is an example source map, taken from the source map spec[0]:
+ *
+ * {
+ * version : 3,
+ * file: "out.js",
+ * sourceRoot : "",
+ * sources: ["foo.js", "bar.js"],
+ * names: ["src", "maps", "are", "fun"],
+ * mappings: "AA,AB;;ABCDE;"
+ * }
+ *
+ * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
+ */
+ function SourceMapConsumer(aSourceMap) {
+ var sourceMap = aSourceMap;
+ if (typeof aSourceMap === 'string') {
+ sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
+ }
+
+ var version = util.getArg(sourceMap, 'version');
+ var sources = util.getArg(sourceMap, 'sources');
+ // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
+ // requires the array) to play nice here.
+ var names = util.getArg(sourceMap, 'names', []);
+ var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
+ var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
+ var mappings = util.getArg(sourceMap, 'mappings');
+ var file = util.getArg(sourceMap, 'file', null);
+
+ // Once again, Sass deviates from the spec and supplies the version as a
+ // string rather than a number, so we use loose equality checking here.
+ if (version != this._version) {
+ throw new Error('Unsupported version: ' + version);
+ }
+
+ // Pass `true` below to allow duplicate names and sources. While source maps
+ // are intended to be compressed and deduplicated, the TypeScript compiler
+ // sometimes generates source maps with duplicates in them. See Github issue
+ // #72 and bugzil.la/889492.
+ this._names = ArraySet.fromArray(names, true);
+ this._sources = ArraySet.fromArray(sources, true);
+
+ this.sourceRoot = sourceRoot;
+ this.sourcesContent = sourcesContent;
+ this._mappings = mappings;
+ this.file = file;
+ }
+
+ /**
+ * Create a SourceMapConsumer from a SourceMapGenerator.
+ *
+ * @param SourceMapGenerator aSourceMap
+ * The source map that will be consumed.
+ * @returns SourceMapConsumer
+ */
+ SourceMapConsumer.fromSourceMap =
+ function SourceMapConsumer_fromSourceMap(aSourceMap) {
+ var smc = Object.create(SourceMapConsumer.prototype);
+
+ smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
+ smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
+ smc.sourceRoot = aSourceMap._sourceRoot;
+ smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
+ smc.sourceRoot);
+ smc.file = aSourceMap._file;
+
+ smc.__generatedMappings = aSourceMap._mappings.slice()
+ .sort(util.compareByGeneratedPositions);
+ smc.__originalMappings = aSourceMap._mappings.slice()
+ .sort(util.compareByOriginalPositions);
+
+ return smc;
+ };
+
+ /**
+ * The version of the source mapping spec that we are consuming.
+ */
+ SourceMapConsumer.prototype._version = 3;
+
+ /**
+ * The list of original sources.
+ */
+ Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
+ get: function () {
+ return this._sources.toArray().map(function (s) {
+ return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
+ }, this);
+ }
+ });
+
+ // `__generatedMappings` and `__originalMappings` are arrays that hold the
+ // parsed mapping coordinates from the source map's "mappings" attribute. They
+ // are lazily instantiated, accessed via the `_generatedMappings` and
+ // `_originalMappings` getters respectively, and we only parse the mappings
+ // and create these arrays once queried for a source location. We jump through
+ // these hoops because there can be many thousands of mappings, and parsing
+ // them is expensive, so we only want to do it if we must.
+ //
+ // Each object in the arrays is of the form:
+ //
+ // {
+ // generatedLine: The line number in the generated code,
+ // generatedColumn: The column number in the generated code,
+ // source: The path to the original source file that generated this
+ // chunk of code,
+ // originalLine: The line number in the original source that
+ // corresponds to this chunk of generated code,
+ // originalColumn: The column number in the original source that
+ // corresponds to this chunk of generated code,
+ // name: The name of the original symbol which generated this chunk of
+ // code.
+ // }
+ //
+ // All properties except for `generatedLine` and `generatedColumn` can be
+ // `null`.
+ //
+ // `_generatedMappings` is ordered by the generated positions.
+ //
+ // `_originalMappings` is ordered by the original positions.
+
+ SourceMapConsumer.prototype.__generatedMappings = null;
+ Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
+ get: function () {
+ if (!this.__generatedMappings) {
+ this.__generatedMappings = [];
+ this.__originalMappings = [];
+ this._parseMappings(this._mappings, this.sourceRoot);
+ }
+
+ return this.__generatedMappings;
+ }
+ });
+
+ SourceMapConsumer.prototype.__originalMappings = null;
+ Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
+ get: function () {
+ if (!this.__originalMappings) {
+ this.__generatedMappings = [];
+ this.__originalMappings = [];
+ this._parseMappings(this._mappings, this.sourceRoot);
+ }
+
+ return this.__originalMappings;
+ }
+ });
+
+ /**
+ * Parse the mappings in a string in to a data structure which we can easily
+ * query (the ordered arrays in the `this.__generatedMappings` and
+ * `this.__originalMappings` properties).
+ */
+ SourceMapConsumer.prototype._parseMappings =
+ function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
+ var generatedLine = 1;
+ var previousGeneratedColumn = 0;
+ var previousOriginalLine = 0;
+ var previousOriginalColumn = 0;
+ var previousSource = 0;
+ var previousName = 0;
+ var mappingSeparator = /^[,;]/;
+ var str = aStr;
+ var mapping;
+ var temp;
+
+ while (str.length > 0) {
+ if (str.charAt(0) === ';') {
+ generatedLine++;
+ str = str.slice(1);
+ previousGeneratedColumn = 0;
+ }
+ else if (str.charAt(0) === ',') {
+ str = str.slice(1);
+ }
+ else {
+ mapping = {};
+ mapping.generatedLine = generatedLine;
+
+ // Generated column.
+ temp = base64VLQ.decode(str);
+ mapping.generatedColumn = previousGeneratedColumn + temp.value;
+ previousGeneratedColumn = mapping.generatedColumn;
+ str = temp.rest;
+
+ if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
+ // Original source.
+ temp = base64VLQ.decode(str);
+ mapping.source = this._sources.at(previousSource + temp.value);
+ previousSource += temp.value;
+ str = temp.rest;
+ if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
+ throw new Error('Found a source, but no line and column');
+ }
+
+ // Original line.
+ temp = base64VLQ.decode(str);
+ mapping.originalLine = previousOriginalLine + temp.value;
+ previousOriginalLine = mapping.originalLine;
+ // Lines are stored 0-based
+ mapping.originalLine += 1;
+ str = temp.rest;
+ if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
+ throw new Error('Found a source and line, but no column');
+ }
+
+ // Original column.
+ temp = base64VLQ.decode(str);
+ mapping.originalColumn = previousOriginalColumn + temp.value;
+ previousOriginalColumn = mapping.originalColumn;
+ str = temp.rest;
+
+ if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
+ // Original name.
+ temp = base64VLQ.decode(str);
+ mapping.name = this._names.at(previousName + temp.value);
+ previousName += temp.value;
+ str = temp.rest;
+ }
+ }
+
+ this.__generatedMappings.push(mapping);
+ if (typeof mapping.originalLine === 'number') {
+ this.__originalMappings.push(mapping);
+ }
+ }
+ }
+
+ this.__originalMappings.sort(util.compareByOriginalPositions);
+ };
+
+ /**
+ * Find the mapping that best matches the hypothetical "needle" mapping that
+ * we are searching for in the given "haystack" of mappings.
+ */
+ SourceMapConsumer.prototype._findMapping =
+ function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
+ aColumnName, aComparator) {
+ // To return the position we are searching for, we must first find the
+ // mapping for the given position and then return the opposite position it
+ // points to. Because the mappings are sorted, we can use binary search to
+ // find the best mapping.
+
+ if (aNeedle[aLineName] <= 0) {
+ throw new TypeError('Line must be greater than or equal to 1, got '
+ + aNeedle[aLineName]);
+ }
+ if (aNeedle[aColumnName] < 0) {
+ throw new TypeError('Column must be greater than or equal to 0, got '
+ + aNeedle[aColumnName]);
+ }
+
+ return binarySearch.search(aNeedle, aMappings, aComparator);
+ };
+
+ /**
+ * Returns the original source, line, and column information for the generated
+ * source's line and column positions provided. The only argument is an object
+ * with the following properties:
+ *
+ * - line: The line number in the generated source.
+ * - column: The column number in the generated source.
+ *
+ * and an object is returned with the following properties:
+ *
+ * - source: The original source file, or null.
+ * - line: The line number in the original source, or null.
+ * - column: The column number in the original source, or null.
+ * - name: The original identifier, or null.
+ */
+ SourceMapConsumer.prototype.originalPositionFor =
+ function SourceMapConsumer_originalPositionFor(aArgs) {
+ var needle = {
+ generatedLine: util.getArg(aArgs, 'line'),
+ generatedColumn: util.getArg(aArgs, 'column')
+ };
+
+ var mapping = this._findMapping(needle,
+ this._generatedMappings,
+ "generatedLine",
+ "generatedColumn",
+ util.compareByGeneratedPositions);
+
+ if (mapping) {
+ var source = util.getArg(mapping, 'source', null);
+ if (source && this.sourceRoot) {
+ source = util.join(this.sourceRoot, source);
+ }
+ return {
+ source: source,
+ line: util.getArg(mapping, 'originalLine', null),
+ column: util.getArg(mapping, 'originalColumn', null),
+ name: util.getArg(mapping, 'name', null)
+ };
+ }
+
+ return {
+ source: null,
+ line: null,
+ column: null,
+ name: null
+ };
+ };
+
+ /**
+ * Returns the original source content. The only argument is the url of the
+ * original source file. Returns null if no original source content is
+ * availible.
+ */
+ SourceMapConsumer.prototype.sourceContentFor =
+ function SourceMapConsumer_sourceContentFor(aSource) {
+ if (!this.sourcesContent) {
+ return null;
+ }
+
+ if (this.sourceRoot) {
+ aSource = util.relative(this.sourceRoot, aSource);
+ }
+
+ if (this._sources.has(aSource)) {
+ return this.sourcesContent[this._sources.indexOf(aSource)];
+ }
+
+ var url;
+ if (this.sourceRoot
+ && (url = util.urlParse(this.sourceRoot))) {
+ // XXX: file:// URIs and absolute paths lead to unexpected behavior for
+ // many users. We can help them out when they expect file:// URIs to
+ // behave like it would if they were running a local HTTP server. See
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
+ var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
+ if (url.scheme == "file"
+ && this._sources.has(fileUriAbsPath)) {
+ return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
+ }
+
+ if ((!url.path || url.path == "/")
+ && this._sources.has("/" + aSource)) {
+ return this.sourcesContent[this._sources.indexOf("/" + aSource)];
+ }
+ }
+
+ throw new Error('"' + aSource + '" is not in the SourceMap.');
+ };
+
+ /**
+ * Returns the generated line and column information for the original source,
+ * line, and column positions provided. The only argument is an object with
+ * the following properties:
+ *
+ * - source: The filename of the original source.
+ * - line: The line number in the original source.
+ * - column: The column number in the original source.
+ *
+ * and an object is returned with the following properties:
+ *
+ * - line: The line number in the generated source, or null.
+ * - column: The column number in the generated source, or null.
+ */
+ SourceMapConsumer.prototype.generatedPositionFor =
+ function SourceMapConsumer_generatedPositionFor(aArgs) {
+ var needle = {
+ source: util.getArg(aArgs, 'source'),
+ originalLine: util.getArg(aArgs, 'line'),
+ originalColumn: util.getArg(aArgs, 'column')
+ };
+
+ if (this.sourceRoot) {
+ needle.source = util.relative(this.sourceRoot, needle.source);
+ }
+
+ var mapping = this._findMapping(needle,
+ this._originalMappings,
+ "originalLine",
+ "originalColumn",
+ util.compareByOriginalPositions);
+
+ if (mapping) {
+ return {
+ line: util.getArg(mapping, 'generatedLine', null),
+ column: util.getArg(mapping, 'generatedColumn', null)
+ };
+ }
+
+ return {
+ line: null,
+ column: null
+ };
+ };
+
+ SourceMapConsumer.GENERATED_ORDER = 1;
+ SourceMapConsumer.ORIGINAL_ORDER = 2;
+
+ /**
+ * Iterate over each mapping between an original source/line/column and a
+ * generated line/column in this source map.
+ *
+ * @param Function aCallback
+ * The function that is called with each mapping.
+ * @param Object aContext
+ * Optional. If specified, this object will be the value of `this` every
+ * time that `aCallback` is called.
+ * @param aOrder
+ * Either `SourceMapConsumer.GENERATED_ORDER` or
+ * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
+ * iterate over the mappings sorted by the generated file's line/column
+ * order or the original's source/line/column order, respectively. Defaults to
+ * `SourceMapConsumer.GENERATED_ORDER`.
+ */
+ SourceMapConsumer.prototype.eachMapping =
+ function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
+ var context = aContext || null;
+ var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
+
+ var mappings;
+ switch (order) {
+ case SourceMapConsumer.GENERATED_ORDER:
+ mappings = this._generatedMappings;
+ break;
+ case SourceMapConsumer.ORIGINAL_ORDER:
+ mappings = this._originalMappings;
+ break;
+ default:
+ throw new Error("Unknown order of iteration.");
+ }
+
+ var sourceRoot = this.sourceRoot;
+ mappings.map(function (mapping) {
+ var source = mapping.source;
+ if (source && sourceRoot) {
+ source = util.join(sourceRoot, source);
+ }
+ return {
+ source: source,
+ generatedLine: mapping.generatedLine,
+ generatedColumn: mapping.generatedColumn,
+ originalLine: mapping.originalLine,
+ originalColumn: mapping.originalColumn,
+ name: mapping.name
+ };
+ }).forEach(aCallback, context);
+ };
+
+ exports.SourceMapConsumer = SourceMapConsumer;
+
+});
+
+},{"./array-set":9,"./base64-vlq":10,"./binary-search":12,"./util":16,"amdefine":17}],14:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var base64VLQ = require('./base64-vlq');
+ var util = require('./util');
+ var ArraySet = require('./array-set').ArraySet;
+
+ /**
+ * An instance of the SourceMapGenerator represents a source map which is
+ * being built incrementally. To create a new one, you must pass an object
+ * with the following properties:
+ *
+ * - file: The filename of the generated source.
+ * - sourceRoot: An optional root for all URLs in this source map.
+ */
+ function SourceMapGenerator(aArgs) {
+ this._file = util.getArg(aArgs, 'file');
+ this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
+ this._sources = new ArraySet();
+ this._names = new ArraySet();
+ this._mappings = [];
+ this._sourcesContents = null;
+ }
+
+ SourceMapGenerator.prototype._version = 3;
+
+ /**
+ * Creates a new SourceMapGenerator based on a SourceMapConsumer
+ *
+ * @param aSourceMapConsumer The SourceMap.
+ */
+ SourceMapGenerator.fromSourceMap =
+ function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
+ var sourceRoot = aSourceMapConsumer.sourceRoot;
+ var generator = new SourceMapGenerator({
+ file: aSourceMapConsumer.file,
+ sourceRoot: sourceRoot
+ });
+ aSourceMapConsumer.eachMapping(function (mapping) {
+ var newMapping = {
+ generated: {
+ line: mapping.generatedLine,
+ column: mapping.generatedColumn
+ }
+ };
+
+ if (mapping.source) {
+ newMapping.source = mapping.source;
+ if (sourceRoot) {
+ newMapping.source = util.relative(sourceRoot, newMapping.source);
+ }
+
+ newMapping.original = {
+ line: mapping.originalLine,
+ column: mapping.originalColumn
+ };
+
+ if (mapping.name) {
+ newMapping.name = mapping.name;
+ }
+ }
+
+ generator.addMapping(newMapping);
+ });
+ aSourceMapConsumer.sources.forEach(function (sourceFile) {
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile);
+ if (content) {
+ generator.setSourceContent(sourceFile, content);
+ }
+ });
+ return generator;
+ };
+
+ /**
+ * Add a single mapping from original source line and column to the generated
+ * source's line and column for this source map being created. The mapping
+ * object should have the following properties:
+ *
+ * - generated: An object with the generated line and column positions.
+ * - original: An object with the original line and column positions.
+ * - source: The original source file (relative to the sourceRoot).
+ * - name: An optional original token name for this mapping.
+ */
+ SourceMapGenerator.prototype.addMapping =
+ function SourceMapGenerator_addMapping(aArgs) {
+ var generated = util.getArg(aArgs, 'generated');
+ var original = util.getArg(aArgs, 'original', null);
+ var source = util.getArg(aArgs, 'source', null);
+ var name = util.getArg(aArgs, 'name', null);
+
+ this._validateMapping(generated, original, source, name);
+
+ if (source && !this._sources.has(source)) {
+ this._sources.add(source);
+ }
+
+ if (name && !this._names.has(name)) {
+ this._names.add(name);
+ }
+
+ this._mappings.push({
+ generatedLine: generated.line,
+ generatedColumn: generated.column,
+ originalLine: original != null && original.line,
+ originalColumn: original != null && original.column,
+ source: source,
+ name: name
+ });
+ };
+
+ /**
+ * Set the source content for a source file.
+ */
+ SourceMapGenerator.prototype.setSourceContent =
+ function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
+ var source = aSourceFile;
+ if (this._sourceRoot) {
+ source = util.relative(this._sourceRoot, source);
+ }
+
+ if (aSourceContent !== null) {
+ // Add the source content to the _sourcesContents map.
+ // Create a new _sourcesContents map if the property is null.
+ if (!this._sourcesContents) {
+ this._sourcesContents = {};
+ }
+ this._sourcesContents[util.toSetString(source)] = aSourceContent;
+ } else {
+ // Remove the source file from the _sourcesContents map.
+ // If the _sourcesContents map is empty, set the property to null.
+ delete this._sourcesContents[util.toSetString(source)];
+ if (Object.keys(this._sourcesContents).length === 0) {
+ this._sourcesContents = null;
+ }
+ }
+ };
+
+ /**
+ * Applies the mappings of a sub-source-map for a specific source file to the
+ * source map being generated. Each mapping to the supplied source file is
+ * rewritten using the supplied source map. Note: The resolution for the
+ * resulting mappings is the minimium of this map and the supplied map.
+ *
+ * @param aSourceMapConsumer The source map to be applied.
+ * @param aSourceFile Optional. The filename of the source file.
+ * If omitted, SourceMapConsumer's file property will be used.
+ */
+ SourceMapGenerator.prototype.applySourceMap =
+ function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) {
+ // If aSourceFile is omitted, we will use the file property of the SourceMap
+ if (!aSourceFile) {
+ aSourceFile = aSourceMapConsumer.file;
+ }
+ var sourceRoot = this._sourceRoot;
+ // Make "aSourceFile" relative if an absolute Url is passed.
+ if (sourceRoot) {
+ aSourceFile = util.relative(sourceRoot, aSourceFile);
+ }
+ // Applying the SourceMap can add and remove items from the sources and
+ // the names array.
+ var newSources = new ArraySet();
+ var newNames = new ArraySet();
+
+ // Find mappings for the "aSourceFile"
+ this._mappings.forEach(function (mapping) {
+ if (mapping.source === aSourceFile && mapping.originalLine) {
+ // Check if it can be mapped by the source map, then update the mapping.
+ var original = aSourceMapConsumer.originalPositionFor({
+ line: mapping.originalLine,
+ column: mapping.originalColumn
+ });
+ if (original.source !== null) {
+ // Copy mapping
+ if (sourceRoot) {
+ mapping.source = util.relative(sourceRoot, original.source);
+ } else {
+ mapping.source = original.source;
+ }
+ mapping.originalLine = original.line;
+ mapping.originalColumn = original.column;
+ if (original.name !== null && mapping.name !== null) {
+ // Only use the identifier name if it's an identifier
+ // in both SourceMaps
+ mapping.name = original.name;
+ }
+ }
+ }
+
+ var source = mapping.source;
+ if (source && !newSources.has(source)) {
+ newSources.add(source);
+ }
+
+ var name = mapping.name;
+ if (name && !newNames.has(name)) {
+ newNames.add(name);
+ }
+
+ }, this);
+ this._sources = newSources;
+ this._names = newNames;
+
+ // Copy sourcesContents of applied map.
+ aSourceMapConsumer.sources.forEach(function (sourceFile) {
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile);
+ if (content) {
+ if (sourceRoot) {
+ sourceFile = util.relative(sourceRoot, sourceFile);
+ }
+ this.setSourceContent(sourceFile, content);
+ }
+ }, this);
+ };
+
+ /**
+ * A mapping can have one of the three levels of data:
+ *
+ * 1. Just the generated position.
+ * 2. The Generated position, original position, and original source.
+ * 3. Generated and original position, original source, as well as a name
+ * token.
+ *
+ * To maintain consistency, we validate that any new mapping being added falls
+ * in to one of these categories.
+ */
+ SourceMapGenerator.prototype._validateMapping =
+ function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
+ aName) {
+ if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
+ && aGenerated.line > 0 && aGenerated.column >= 0
+ && !aOriginal && !aSource && !aName) {
+ // Case 1.
+ return;
+ }
+ else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
+ && aOriginal && 'line' in aOriginal && 'column' in aOriginal
+ && aGenerated.line > 0 && aGenerated.column >= 0
+ && aOriginal.line > 0 && aOriginal.column >= 0
+ && aSource) {
+ // Cases 2 and 3.
+ return;
+ }
+ else {
+ throw new Error('Invalid mapping: ' + JSON.stringify({
+ generated: aGenerated,
+ source: aSource,
+ orginal: aOriginal,
+ name: aName
+ }));
+ }
+ };
+
+ /**
+ * Serialize the accumulated mappings in to the stream of base 64 VLQs
+ * specified by the source map format.
+ */
+ SourceMapGenerator.prototype._serializeMappings =
+ function SourceMapGenerator_serializeMappings() {
+ var previousGeneratedColumn = 0;
+ var previousGeneratedLine = 1;
+ var previousOriginalColumn = 0;
+ var previousOriginalLine = 0;
+ var previousName = 0;
+ var previousSource = 0;
+ var result = '';
+ var mapping;
+
+ // The mappings must be guaranteed to be in sorted order before we start
+ // serializing them or else the generated line numbers (which are defined
+ // via the ';' separators) will be all messed up. Note: it might be more
+ // performant to maintain the sorting as we insert them, rather than as we
+ // serialize them, but the big O is the same either way.
+ this._mappings.sort(util.compareByGeneratedPositions);
+
+ for (var i = 0, len = this._mappings.length; i < len; i++) {
+ mapping = this._mappings[i];
+
+ if (mapping.generatedLine !== previousGeneratedLine) {
+ previousGeneratedColumn = 0;
+ while (mapping.generatedLine !== previousGeneratedLine) {
+ result += ';';
+ previousGeneratedLine++;
+ }
+ }
+ else {
+ if (i > 0) {
+ if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) {
+ continue;
+ }
+ result += ',';
+ }
+ }
+
+ result += base64VLQ.encode(mapping.generatedColumn
+ - previousGeneratedColumn);
+ previousGeneratedColumn = mapping.generatedColumn;
+
+ if (mapping.source) {
+ result += base64VLQ.encode(this._sources.indexOf(mapping.source)
+ - previousSource);
+ previousSource = this._sources.indexOf(mapping.source);
+
+ // lines are stored 0-based in SourceMap spec version 3
+ result += base64VLQ.encode(mapping.originalLine - 1
+ - previousOriginalLine);
+ previousOriginalLine = mapping.originalLine - 1;
+
+ result += base64VLQ.encode(mapping.originalColumn
+ - previousOriginalColumn);
+ previousOriginalColumn = mapping.originalColumn;
+
+ if (mapping.name) {
+ result += base64VLQ.encode(this._names.indexOf(mapping.name)
+ - previousName);
+ previousName = this._names.indexOf(mapping.name);
+ }
+ }
+ }
+
+ return result;
+ };
+
+ SourceMapGenerator.prototype._generateSourcesContent =
+ function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
+ return aSources.map(function (source) {
+ if (!this._sourcesContents) {
+ return null;
+ }
+ if (aSourceRoot) {
+ source = util.relative(aSourceRoot, source);
+ }
+ var key = util.toSetString(source);
+ return Object.prototype.hasOwnProperty.call(this._sourcesContents,
+ key)
+ ? this._sourcesContents[key]
+ : null;
+ }, this);
+ };
+
+ /**
+ * Externalize the source map.
+ */
+ SourceMapGenerator.prototype.toJSON =
+ function SourceMapGenerator_toJSON() {
+ var map = {
+ version: this._version,
+ file: this._file,
+ sources: this._sources.toArray(),
+ names: this._names.toArray(),
+ mappings: this._serializeMappings()
+ };
+ if (this._sourceRoot) {
+ map.sourceRoot = this._sourceRoot;
+ }
+ if (this._sourcesContents) {
+ map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
+ }
+
+ return map;
+ };
+
+ /**
+ * Render the source map being generated to a string.
+ */
+ SourceMapGenerator.prototype.toString =
+ function SourceMapGenerator_toString() {
+ return JSON.stringify(this);
+ };
+
+ exports.SourceMapGenerator = SourceMapGenerator;
+
+});
+
+},{"./array-set":9,"./base64-vlq":10,"./util":16,"amdefine":17}],15:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;
+ var util = require('./util');
+
+ /**
+ * SourceNodes provide a way to abstract over interpolating/concatenating
+ * snippets of generated JavaScript source code while maintaining the line and
+ * column information associated with the original source code.
+ *
+ * @param aLine The original line number.
+ * @param aColumn The original column number.
+ * @param aSource The original source's filename.
+ * @param aChunks Optional. An array of strings which are snippets of
+ * generated JS, or other SourceNodes.
+ * @param aName The original identifier.
+ */
+ function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
+ this.children = [];
+ this.sourceContents = {};
+ this.line = aLine === undefined ? null : aLine;
+ this.column = aColumn === undefined ? null : aColumn;
+ this.source = aSource === undefined ? null : aSource;
+ this.name = aName === undefined ? null : aName;
+ if (aChunks != null) this.add(aChunks);
+ }
+
+ /**
+ * Creates a SourceNode from generated code and a SourceMapConsumer.
+ *
+ * @param aGeneratedCode The generated code
+ * @param aSourceMapConsumer The SourceMap for the generated code
+ */
+ SourceNode.fromStringWithSourceMap =
+ function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
+ // The SourceNode we want to fill with the generated code
+ // and the SourceMap
+ var node = new SourceNode();
+
+ // The generated code
+ // Processed fragments are removed from this array.
+ var remainingLines = aGeneratedCode.split('\n');
+
+ // We need to remember the position of "remainingLines"
+ var lastGeneratedLine = 1, lastGeneratedColumn = 0;
+
+ // The generate SourceNodes we need a code range.
+ // To extract it current and last mapping is used.
+ // Here we store the last mapping.
+ var lastMapping = null;
+
+ aSourceMapConsumer.eachMapping(function (mapping) {
+ if (lastMapping === null) {
+ // We add the generated code until the first mapping
+ // to the SourceNode without any mapping.
+ // Each line is added as separate string.
+ while (lastGeneratedLine < mapping.generatedLine) {
+ node.add(remainingLines.shift() + "\n");
+ lastGeneratedLine++;
+ }
+ if (lastGeneratedColumn < mapping.generatedColumn) {
+ var nextLine = remainingLines[0];
+ node.add(nextLine.substr(0, mapping.generatedColumn));
+ remainingLines[0] = nextLine.substr(mapping.generatedColumn);
+ lastGeneratedColumn = mapping.generatedColumn;
+ }
+ } else {
+ // We add the code from "lastMapping" to "mapping":
+ // First check if there is a new line in between.
+ if (lastGeneratedLine < mapping.generatedLine) {
+ var code = "";
+ // Associate full lines with "lastMapping"
+ do {
+ code += remainingLines.shift() + "\n";
+ lastGeneratedLine++;
+ lastGeneratedColumn = 0;
+ } while (lastGeneratedLine < mapping.generatedLine);
+ // When we reached the correct line, we add code until we
+ // reach the correct column too.
+ if (lastGeneratedColumn < mapping.generatedColumn) {
+ var nextLine = remainingLines[0];
+ code += nextLine.substr(0, mapping.generatedColumn);
+ remainingLines[0] = nextLine.substr(mapping.generatedColumn);
+ lastGeneratedColumn = mapping.generatedColumn;
+ }
+ // Create the SourceNode.
+ addMappingWithCode(lastMapping, code);
+ } else {
+ // There is no new line in between.
+ // Associate the code between "lastGeneratedColumn" and
+ // "mapping.generatedColumn" with "lastMapping"
+ var nextLine = remainingLines[0];
+ var code = nextLine.substr(0, mapping.generatedColumn -
+ lastGeneratedColumn);
+ remainingLines[0] = nextLine.substr(mapping.generatedColumn -
+ lastGeneratedColumn);
+ lastGeneratedColumn = mapping.generatedColumn;
+ addMappingWithCode(lastMapping, code);
+ }
+ }
+ lastMapping = mapping;
+ }, this);
+ // We have processed all mappings.
+ // Associate the remaining code in the current line with "lastMapping"
+ // and add the remaining lines without any mapping
+ addMappingWithCode(lastMapping, remainingLines.join("\n"));
+
+ // Copy sourcesContent into SourceNode
+ aSourceMapConsumer.sources.forEach(function (sourceFile) {
+ var content = aSourceMapConsumer.sourceContentFor(sourceFile);
+ if (content) {
+ node.setSourceContent(sourceFile, content);
+ }
+ });
+
+ return node;
+
+ function addMappingWithCode(mapping, code) {
+ if (mapping === null || mapping.source === undefined) {
+ node.add(code);
+ } else {
+ node.add(new SourceNode(mapping.originalLine,
+ mapping.originalColumn,
+ mapping.source,
+ code,
+ mapping.name));
+ }
+ }
+ };
+
+ /**
+ * Add a chunk of generated JS to this source node.
+ *
+ * @param aChunk A string snippet of generated JS code, another instance of
+ * SourceNode, or an array where each member is one of those things.
+ */
+ SourceNode.prototype.add = function SourceNode_add(aChunk) {
+ if (Array.isArray(aChunk)) {
+ aChunk.forEach(function (chunk) {
+ this.add(chunk);
+ }, this);
+ }
+ else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
+ if (aChunk) {
+ this.children.push(aChunk);
+ }
+ }
+ else {
+ throw new TypeError(
+ "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
+ );
+ }
+ return this;
+ };
+
+ /**
+ * Add a chunk of generated JS to the beginning of this source node.
+ *
+ * @param aChunk A string snippet of generated JS code, another instance of
+ * SourceNode, or an array where each member is one of those things.
+ */
+ SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
+ if (Array.isArray(aChunk)) {
+ for (var i = aChunk.length-1; i >= 0; i--) {
+ this.prepend(aChunk[i]);
+ }
+ }
+ else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
+ this.children.unshift(aChunk);
+ }
+ else {
+ throw new TypeError(
+ "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
+ );
+ }
+ return this;
+ };
+
+ /**
+ * Walk over the tree of JS snippets in this node and its children. The
+ * walking function is called once for each snippet of JS and is passed that
+ * snippet and the its original associated source's line/column location.
+ *
+ * @param aFn The traversal function.
+ */
+ SourceNode.prototype.walk = function SourceNode_walk(aFn) {
+ var chunk;
+ for (var i = 0, len = this.children.length; i < len; i++) {
+ chunk = this.children[i];
+ if (chunk instanceof SourceNode) {
+ chunk.walk(aFn);
+ }
+ else {
+ if (chunk !== '') {
+ aFn(chunk, { source: this.source,
+ line: this.line,
+ column: this.column,
+ name: this.name });
+ }
+ }
+ }
+ };
+
+ /**
+ * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
+ * each of `this.children`.
+ *
+ * @param aSep The separator.
+ */
+ SourceNode.prototype.join = function SourceNode_join(aSep) {
+ var newChildren;
+ var i;
+ var len = this.children.length;
+ if (len > 0) {
+ newChildren = [];
+ for (i = 0; i < len-1; i++) {
+ newChildren.push(this.children[i]);
+ newChildren.push(aSep);
+ }
+ newChildren.push(this.children[i]);
+ this.children = newChildren;
+ }
+ return this;
+ };
+
+ /**
+ * Call String.prototype.replace on the very right-most source snippet. Useful
+ * for trimming whitespace from the end of a source node, etc.
+ *
+ * @param aPattern The pattern to replace.
+ * @param aReplacement The thing to replace the pattern with.
+ */
+ SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
+ var lastChild = this.children[this.children.length - 1];
+ if (lastChild instanceof SourceNode) {
+ lastChild.replaceRight(aPattern, aReplacement);
+ }
+ else if (typeof lastChild === 'string') {
+ this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
+ }
+ else {
+ this.children.push(''.replace(aPattern, aReplacement));
+ }
+ return this;
+ };
+
+ /**
+ * Set the source content for a source file. This will be added to the SourceMapGenerator
+ * in the sourcesContent field.
+ *
+ * @param aSourceFile The filename of the source file
+ * @param aSourceContent The content of the source file
+ */
+ SourceNode.prototype.setSourceContent =
+ function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
+ this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
+ };
+
+ /**
+ * Walk over the tree of SourceNodes. The walking function is called for each
+ * source file content and is passed the filename and source content.
+ *
+ * @param aFn The traversal function.
+ */
+ SourceNode.prototype.walkSourceContents =
+ function SourceNode_walkSourceContents(aFn) {
+ for (var i = 0, len = this.children.length; i < len; i++) {
+ if (this.children[i] instanceof SourceNode) {
+ this.children[i].walkSourceContents(aFn);
+ }
+ }
+
+ var sources = Object.keys(this.sourceContents);
+ for (var i = 0, len = sources.length; i < len; i++) {
+ aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
+ }
+ };
+
+ /**
+ * Return the string representation of this source node. Walks over the tree
+ * and concatenates all the various snippets together to one string.
+ */
+ SourceNode.prototype.toString = function SourceNode_toString() {
+ var str = "";
+ this.walk(function (chunk) {
+ str += chunk;
+ });
+ return str;
+ };
+
+ /**
+ * Returns the string representation of this source node along with a source
+ * map.
+ */
+ SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
+ var generated = {
+ code: "",
+ line: 1,
+ column: 0
+ };
+ var map = new SourceMapGenerator(aArgs);
+ var sourceMappingActive = false;
+ var lastOriginalSource = null;
+ var lastOriginalLine = null;
+ var lastOriginalColumn = null;
+ var lastOriginalName = null;
+ this.walk(function (chunk, original) {
+ generated.code += chunk;
+ if (original.source !== null
+ && original.line !== null
+ && original.column !== null) {
+ if(lastOriginalSource !== original.source
+ || lastOriginalLine !== original.line
+ || lastOriginalColumn !== original.column
+ || lastOriginalName !== original.name) {
+ map.addMapping({
+ source: original.source,
+ original: {
+ line: original.line,
+ column: original.column
+ },
+ generated: {
+ line: generated.line,
+ column: generated.column
+ },
+ name: original.name
+ });
+ }
+ lastOriginalSource = original.source;
+ lastOriginalLine = original.line;
+ lastOriginalColumn = original.column;
+ lastOriginalName = original.name;
+ sourceMappingActive = true;
+ } else if (sourceMappingActive) {
+ map.addMapping({
+ generated: {
+ line: generated.line,
+ column: generated.column
+ }
+ });
+ lastOriginalSource = null;
+ sourceMappingActive = false;
+ }
+ chunk.split('').forEach(function (ch) {
+ if (ch === '\n') {
+ generated.line++;
+ generated.column = 0;
+ } else {
+ generated.column++;
+ }
+ });
+ });
+ this.walkSourceContents(function (sourceFile, sourceContent) {
+ map.setSourceContent(sourceFile, sourceContent);
+ });
+
+ return { code: generated.code, map: map };
+ };
+
+ exports.SourceNode = SourceNode;
+
+});
+
+},{"./source-map-generator":14,"./util":16,"amdefine":17}],16:[function(require,module,exports){
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/*
+ * Copyright 2011 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE or:
+ * http://opensource.org/licenses/BSD-3-Clause
+ */
+if (typeof define !== 'function') {
+ var define = require('amdefine')(module, require);
+}
+define(function (require, exports, module) {
+
+ /**
+ * This is a helper function for getting values from parameter/options
+ * objects.
+ *
+ * @param args The object we are extracting values from
+ * @param name The name of the property we are getting.
+ * @param defaultValue An optional value to return if the property is missing
+ * from the object. If this is not specified and the property is missing, an
+ * error will be thrown.
+ */
+ function getArg(aArgs, aName, aDefaultValue) {
+ if (aName in aArgs) {
+ return aArgs[aName];
+ } else if (arguments.length === 3) {
+ return aDefaultValue;
+ } else {
+ throw new Error('"' + aName + '" is a required argument.');
+ }
+ }
+ exports.getArg = getArg;
+
+ var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
+ var dataUrlRegexp = /^data:.+\,.+/;
+
+ function urlParse(aUrl) {
+ var match = aUrl.match(urlRegexp);
+ if (!match) {
+ return null;
+ }
+ return {
+ scheme: match[1],
+ auth: match[3],
+ host: match[4],
+ port: match[6],
+ path: match[7]
+ };
+ }
+ exports.urlParse = urlParse;
+
+ function urlGenerate(aParsedUrl) {
+ var url = aParsedUrl.scheme + "://";
+ if (aParsedUrl.auth) {
+ url += aParsedUrl.auth + "@"
+ }
+ if (aParsedUrl.host) {
+ url += aParsedUrl.host;
+ }
+ if (aParsedUrl.port) {
+ url += ":" + aParsedUrl.port
+ }
+ if (aParsedUrl.path) {
+ url += aParsedUrl.path;
+ }
+ return url;
+ }
+ exports.urlGenerate = urlGenerate;
+
+ function join(aRoot, aPath) {
+ var url;
+
+ if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) {
+ return aPath;
+ }
+
+ if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
+ url.path = aPath;
+ return urlGenerate(url);
+ }
+
+ return aRoot.replace(/\/$/, '') + '/' + aPath;
+ }
+ exports.join = join;
+
+ /**
+ * Because behavior goes wacky when you set `__proto__` on objects, we
+ * have to prefix all the strings in our set with an arbitrary character.
+ *
+ * See https://github.com/mozilla/source-map/pull/31 and
+ * https://github.com/mozilla/source-map/issues/30
+ *
+ * @param String aStr
+ */
+ function toSetString(aStr) {
+ return '$' + aStr;
+ }
+ exports.toSetString = toSetString;
+
+ function fromSetString(aStr) {
+ return aStr.substr(1);
+ }
+ exports.fromSetString = fromSetString;
+
+ function relative(aRoot, aPath) {
+ aRoot = aRoot.replace(/\/$/, '');
+
+ var url = urlParse(aRoot);
+ if (aPath.charAt(0) == "/" && url && url.path == "/") {
+ return aPath.slice(1);
+ }
+
+ return aPath.indexOf(aRoot + '/') === 0
+ ? aPath.substr(aRoot.length + 1)
+ : aPath;
+ }
+ exports.relative = relative;
+
+ function strcmp(aStr1, aStr2) {
+ var s1 = aStr1 || "";
+ var s2 = aStr2 || "";
+ return (s1 > s2) - (s1 < s2);
+ }
+
+ /**
+ * Comparator between two mappings where the original positions are compared.
+ *
+ * Optionally pass in `true` as `onlyCompareGenerated` to consider two
+ * mappings with the same original source/line/column, but different generated
+ * line and column the same. Useful when searching for a mapping with a
+ * stubbed out mapping.
+ */
+ function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
+ var cmp;
+
+ cmp = strcmp(mappingA.source, mappingB.source);
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.originalLine - mappingB.originalLine;
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.originalColumn - mappingB.originalColumn;
+ if (cmp || onlyCompareOriginal) {
+ return cmp;
+ }
+
+ cmp = strcmp(mappingA.name, mappingB.name);
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.generatedLine - mappingB.generatedLine;
+ if (cmp) {
+ return cmp;
+ }
+
+ return mappingA.generatedColumn - mappingB.generatedColumn;
+ };
+ exports.compareByOriginalPositions = compareByOriginalPositions;
+
+ /**
+ * Comparator between two mappings where the generated positions are
+ * compared.
+ *
+ * Optionally pass in `true` as `onlyCompareGenerated` to consider two
+ * mappings with the same generated line and column, but different
+ * source/name/original line and column the same. Useful when searching for a
+ * mapping with a stubbed out mapping.
+ */
+ function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) {
+ var cmp;
+
+ cmp = mappingA.generatedLine - mappingB.generatedLine;
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.generatedColumn - mappingB.generatedColumn;
+ if (cmp || onlyCompareGenerated) {
+ return cmp;
+ }
+
+ cmp = strcmp(mappingA.source, mappingB.source);
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.originalLine - mappingB.originalLine;
+ if (cmp) {
+ return cmp;
+ }
+
+ cmp = mappingA.originalColumn - mappingB.originalColumn;
+ if (cmp) {
+ return cmp;
+ }
+
+ return strcmp(mappingA.name, mappingB.name);
+ };
+ exports.compareByGeneratedPositions = compareByGeneratedPositions;
+
+});
+
+},{"amdefine":17}],17:[function(require,module,exports){
+var process=require("__browserify_process"),__filename="/../node_modules/jstransform/node_modules/source-map/node_modules/amdefine/amdefine.js";/** vim: et:ts=4:sw=4:sts=4
+ * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/amdefine for details
+ */
+
+/*jslint node: true */
+/*global module, process */
+'use strict';
+
+/**
+ * Creates a define for node.
+ * @param {Object} module the "module" object that is defined by Node for the
+ * current module.
+ * @param {Function} [requireFn]. Node's require function for the current module.
+ * It only needs to be passed in Node versions before 0.5, when module.require
+ * did not exist.
+ * @returns {Function} a define function that is usable for the current node
+ * module.
+ */
+function amdefine(module, requireFn) {
+ 'use strict';
+ var defineCache = {},
+ loaderCache = {},
+ alreadyCalled = false,
+ path = require('path'),
+ makeRequire, stringRequire;
+
+ /**
+ * Trims the . and .. from an array of path segments.
+ * It will keep a leading path segment if a .. will become
+ * the first path segment, to help with module name lookups,
+ * which act like paths, but can be remapped. But the end result,
+ * all paths that use this function should look normalized.
+ * NOTE: this method MODIFIES the input array.
+ * @param {Array} ary the array of path segments.
+ */
+ function trimDots(ary) {
+ var i, part;
+ for (i = 0; ary[i]; i+= 1) {
+ part = ary[i];
+ if (part === '.') {
+ ary.splice(i, 1);
+ i -= 1;
+ } else if (part === '..') {
+ if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
+ //End of the line. Keep at least one non-dot
+ //path segment at the front so it can be mapped
+ //correctly to disk. Otherwise, there is likely
+ //no path mapping for a path starting with '..'.
+ //This can still fail, but catches the most reasonable
+ //uses of ..
+ break;
+ } else if (i > 0) {
+ ary.splice(i - 1, 2);
+ i -= 2;
+ }
+ }
+ }
+ }
+
+ function normalize(name, baseName) {
+ var baseParts;
+
+ //Adjust any relative paths.
+ if (name && name.charAt(0) === '.') {
+ //If have a base name, try to normalize against it,
+ //otherwise, assume it is a top-level require that will
+ //be relative to baseUrl in the end.
+ if (baseName) {
+ baseParts = baseName.split('/');
+ baseParts = baseParts.slice(0, baseParts.length - 1);
+ baseParts = baseParts.concat(name.split('/'));
+ trimDots(baseParts);
+ name = baseParts.join('/');
+ }
+ }
+
+ return name;
+ }
+
+ /**
+ * Create the normalize() function passed to a loader plugin's
+ * normalize method.
+ */
+ function makeNormalize(relName) {
+ return function (name) {
+ return normalize(name, relName);
+ };
+ }
+
+ function makeLoad(id) {
+ function load(value) {
+ loaderCache[id] = value;
+ }
+
+ load.fromText = function (id, text) {
+ //This one is difficult because the text can/probably uses
+ //define, and any relative paths and requires should be relative
+ //to that id was it would be found on disk. But this would require
+ //bootstrapping a module/require fairly deeply from node core.
+ //Not sure how best to go about that yet.
+ throw new Error('amdefine does not implement load.fromText');
+ };
+
+ return load;
+ }
+
+ makeRequire = function (systemRequire, exports, module, relId) {
+ function amdRequire(deps, callback) {
+ if (typeof deps === 'string') {
+ //Synchronous, single module require('')
+ return stringRequire(systemRequire, exports, module, deps, relId);
+ } else {
+ //Array of dependencies with a callback.
+
+ //Convert the dependencies to modules.
+ deps = deps.map(function (depName) {
+ return stringRequire(systemRequire, exports, module, depName, relId);
+ });
+
+ //Wait for next tick to call back the require call.
+ process.nextTick(function () {
+ callback.apply(null, deps);
+ });
+ }
+ }
+
+ amdRequire.toUrl = function (filePath) {
+ if (filePath.indexOf('.') === 0) {
+ return normalize(filePath, path.dirname(module.filename));
+ } else {
+ return filePath;
+ }
+ };
+
+ return amdRequire;
+ };
+
+ //Favor explicit value, passed in if the module wants to support Node 0.4.
+ requireFn = requireFn || function req() {
+ return module.require.apply(module, arguments);
+ };
+
+ function runFactory(id, deps, factory) {
+ var r, e, m, result;
+
+ if (id) {
+ e = loaderCache[id] = {};
+ m = {
+ id: id,
+ uri: __filename,
+ exports: e
+ };
+ r = makeRequire(requireFn, e, m, id);
+ } else {
+ //Only support one define call per file
+ if (alreadyCalled) {
+ throw new Error('amdefine with no module ID cannot be called more than once per file.');
+ }
+ alreadyCalled = true;
+
+ //Use the real variables from node
+ //Use module.exports for exports, since
+ //the exports in here is amdefine exports.
+ e = module.exports;
+ m = module;
+ r = makeRequire(requireFn, e, m, module.id);
+ }
+
+ //If there are dependencies, they are strings, so need
+ //to convert them to dependency values.
+ if (deps) {
+ deps = deps.map(function (depName) {
+ return r(depName);
+ });
+ }
+
+ //Call the factory with the right dependencies.
+ if (typeof factory === 'function') {
+ result = factory.apply(m.exports, deps);
+ } else {
+ result = factory;
+ }
+
+ if (result !== undefined) {
+ m.exports = result;
+ if (id) {
+ loaderCache[id] = m.exports;
+ }
+ }
+ }
+
+ stringRequire = function (systemRequire, exports, module, id, relId) {
+ //Split the ID by a ! so that
+ var index = id.indexOf('!'),
+ originalId = id,
+ prefix, plugin;
+
+ if (index === -1) {
+ id = normalize(id, relId);
+
+ //Straight module lookup. If it is one of the special dependencies,
+ //deal with it, otherwise, delegate to node.
+ if (id === 'require') {
+ return makeRequire(systemRequire, exports, module, relId);
+ } else if (id === 'exports') {
+ return exports;
+ } else if (id === 'module') {
+ return module;
+ } else if (loaderCache.hasOwnProperty(id)) {
+ return loaderCache[id];
+ } else if (defineCache[id]) {
+ runFactory.apply(null, defineCache[id]);
+ return loaderCache[id];
+ } else {
+ if(systemRequire) {
+ return systemRequire(originalId);
+ } else {
+ throw new Error('No module with ID: ' + id);
+ }
+ }
+ } else {
+ //There is a plugin in play.
+ prefix = id.substring(0, index);
+ id = id.substring(index + 1, id.length);
+
+ plugin = stringRequire(systemRequire, exports, module, prefix, relId);
+
+ if (plugin.normalize) {
+ id = plugin.normalize(id, makeNormalize(relId));
+ } else {
+ //Normalize the ID normally.
+ id = normalize(id, relId);
+ }
+
+ if (loaderCache[id]) {
+ return loaderCache[id];
+ } else {
+ plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
+
+ return loaderCache[id];
+ }
+ }
+ };
+
+ //Create a define function specific to the module asking for amdefine.
+ function define(id, deps, factory) {
+ if (Array.isArray(id)) {
+ factory = deps;
+ deps = id;
+ id = undefined;
+ } else if (typeof id !== 'string') {
+ factory = id;
+ id = deps = undefined;
+ }
+
+ if (deps && !Array.isArray(deps)) {
+ factory = deps;
+ deps = undefined;
+ }
+
+ if (!deps) {
+ deps = ['require', 'exports', 'module'];
+ }
+
+ //Set up properties for this module. If an ID, then use
+ //internal cache. If no ID, then use the external variables
+ //for this node module.
+ if (id) {
+ //Put the module in deep freeze until there is a
+ //require call for it.
+ defineCache[id] = [id, deps, factory];
+ } else {
+ runFactory(id, deps, factory);
+ }
+ }
+
+ //define.require, which has access to all the values in the
+ //cache. Useful for AMD modules that all have IDs in the file,
+ //but need to finally export a value to node based on one of those
+ //IDs.
+ define.require = function (id) {
+ if (loaderCache[id]) {
+ return loaderCache[id];
+ }
+
+ if (defineCache[id]) {
+ runFactory.apply(null, defineCache[id]);
+ return loaderCache[id];
+ }
+ };
+
+ define.amd = {};
+
+ return define;
+}
+
+module.exports = amdefine;
+
+},{"__browserify_process":1,"path":5}],18:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var docblockRe = /^\s*(\/\*\*(.|\r?\n)*?\*\/)/;
+var ltrimRe = /^\s*/;
+/**
+ * @param {String} contents
+ * @return {String}
+ */
+function extract(contents) {
+ var match = contents.match(docblockRe);
+ if (match) {
+ return match[0].replace(ltrimRe, '') || '';
+ }
+ return '';
+}
+
+
+var commentStartRe = /^\/\*\*?/;
+var commentEndRe = /\*+\/$/;
+var wsRe = /[\t ]+/g;
+var stringStartRe = /(\r?\n|^) *\*/g;
+var multilineRe = /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g;
+var propertyRe = /(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g;
+
+/**
+ * @param {String} contents
+ * @return {Array}
+ */
+function parse(docblock) {
+ docblock = docblock
+ .replace(commentStartRe, '')
+ .replace(commentEndRe, '')
+ .replace(wsRe, ' ')
+ .replace(stringStartRe, '$1');
+
+ // Normalize multi-line directives
+ var prev = '';
+ while (prev != docblock) {
+ prev = docblock;
+ docblock = docblock.replace(multilineRe, "\n$1 $2\n");
+ }
+ docblock = docblock.trim();
+
+ var result = [];
+ var match;
+ while (match = propertyRe.exec(docblock)) {
+ result.push([match[1], match[2]]);
+ }
+
+ return result;
+}
+
+/**
+ * Same as parse but returns an object of prop: value instead of array of paris
+ * If a property appers more than once the last one will be returned
+ *
+ * @param {String} contents
+ * @return {Object}
+ */
+function parseAsObject(docblock) {
+ var pairs = parse(docblock);
+ var result = {};
+ for (var i = 0; i < pairs.length; i++) {
+ result[pairs[i][0]] = pairs[i][1];
+ }
+ return result;
+}
+
+
+exports.extract = extract;
+exports.parse = parse;
+exports.parseAsObject = parseAsObject;
+
+},{}],19:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*jslint node: true*/
+"use strict";
+
+/**
+ * Syntax transfomer for javascript. Takes the source in, spits the source
+ * out.
+ *
+ * Parses input source with esprima, applies the given list of visitors to the
+ * AST tree, and returns the resulting output.
+ */
+var esprima = require('esprima-fb');
+var utils = require('./utils');
+
+var Syntax = esprima.Syntax;
+
+/**
+ * @param {object} node
+ * @param {object} parentNode
+ * @return {boolean}
+ */
+function _nodeIsClosureScopeBoundary(node, parentNode) {
+ if (node.type === Syntax.Program) {
+ return true;
+ }
+
+ var parentIsFunction =
+ parentNode.type === Syntax.FunctionDeclaration
+ || parentNode.type === Syntax.FunctionExpression;
+
+ return node.type === Syntax.BlockStatement && parentIsFunction;
+}
+
+function _nodeIsBlockScopeBoundary(node, parentNode) {
+ if (node.type === Syntax.Program) {
+ return false;
+ }
+
+ return node.type === Syntax.BlockStatement
+ && parentNode.type === Syntax.CatchClause;
+}
+
+/**
+ * @param {object} node
+ * @param {function} visitor
+ * @param {array} path
+ * @param {object} state
+ */
+function traverse(node, path, state) {
+ // Create a scope stack entry if this is the first node we've encountered in
+ // its local scope
+ var parentNode = path[0];
+ if (!Array.isArray(node) && state.localScope.parentNode !== parentNode) {
+ if (_nodeIsClosureScopeBoundary(node, parentNode)) {
+ var scopeIsStrict =
+ state.scopeIsStrict
+ || node.body.length > 0
+ && node.body[0].type === Syntax.ExpressionStatement
+ && node.body[0].expression.type === Syntax.Literal
+ && node.body[0].expression.value === 'use strict';
+
+ if (node.type === Syntax.Program) {
+ state = utils.updateState(state, {
+ scopeIsStrict: scopeIsStrict
+ });
+ } else {
+ state = utils.updateState(state, {
+ localScope: {
+ parentNode: parentNode,
+ parentScope: state.localScope,
+ identifiers: {}
+ },
+ scopeIsStrict: scopeIsStrict
+ });
+
+ // All functions have an implicit 'arguments' object in scope
+ state.localScope.identifiers['arguments'] = true;
+
+ // Include function arg identifiers in the scope boundaries of the
+ // function
+ if (parentNode.params.length > 0) {
+ var param;
+ for (var i = 0; i < parentNode.params.length; i++) {
+ param = parentNode.params[i];
+ if (param.type === Syntax.Identifier) {
+ state.localScope.identifiers[param.name] = true;
+ }
+ }
+ }
+
+ // Named FunctionExpressions scope their name within the body block of
+ // themselves only
+ if (parentNode.type === Syntax.FunctionExpression && parentNode.id) {
+ state.localScope.identifiers[parentNode.id.name] = true;
+ }
+ }
+
+ // Traverse and find all local identifiers in this closure first to
+ // account for function/variable declaration hoisting
+ collectClosureIdentsAndTraverse(node, path, state);
+ }
+
+ if (_nodeIsBlockScopeBoundary(node, parentNode)) {
+ state = utils.updateState(state, {
+ localScope: {
+ parentNode: parentNode,
+ parentScope: state.localScope,
+ identifiers: {}
+ }
+ });
+
+ if (parentNode.type === Syntax.CatchClause) {
+ state.localScope.identifiers[parentNode.param.name] = true;
+ }
+ collectBlockIdentsAndTraverse(node, path, state);
+ }
+ }
+
+ // Only catchup() before and after traversing a child node
+ function traverser(node, path, state) {
+ node.range && utils.catchup(node.range[0], state);
+ traverse(node, path, state);
+ node.range && utils.catchup(node.range[1], state);
+ }
+
+ utils.analyzeAndTraverse(walker, traverser, node, path, state);
+}
+
+function collectClosureIdentsAndTraverse(node, path, state) {
+ utils.analyzeAndTraverse(
+ visitLocalClosureIdentifiers,
+ collectClosureIdentsAndTraverse,
+ node,
+ path,
+ state
+ );
+}
+
+function collectBlockIdentsAndTraverse(node, path, state) {
+ utils.analyzeAndTraverse(
+ visitLocalBlockIdentifiers,
+ collectBlockIdentsAndTraverse,
+ node,
+ path,
+ state
+ );
+}
+
+function visitLocalClosureIdentifiers(node, path, state) {
+ var identifiers = state.localScope.identifiers;
+ switch (node.type) {
+ case Syntax.FunctionExpression:
+ // Function expressions don't get their names (if there is one) added to
+ // the closure scope they're defined in
+ return false;
+ case Syntax.ClassDeclaration:
+ case Syntax.ClassExpression:
+ case Syntax.FunctionDeclaration:
+ if (node.id) {
+ identifiers[node.id.name] = true;
+ }
+ return false;
+ case Syntax.VariableDeclarator:
+ if (path[0].kind === 'var') {
+ identifiers[node.id.name] = true;
+ }
+ break;
+ }
+}
+
+function visitLocalBlockIdentifiers(node, path, state) {
+ // TODO: Support 'let' here...maybe...one day...or something...
+ if (node.type === Syntax.CatchClause) {
+ return false;
+ }
+}
+
+function walker(node, path, state) {
+ var visitors = state.g.visitors;
+ for (var i = 0; i < visitors.length; i++) {
+ if (visitors[i].test(node, path, state)) {
+ return visitors[i](traverse, node, path, state);
+ }
+ }
+}
+
+/**
+ * Applies all available transformations to the source
+ * @param {array} visitors
+ * @param {string} source
+ * @param {?object} options
+ * @return {object}
+ */
+function transform(visitors, source, options) {
+ options = options || {};
+
+ var ast;
+ try {
+ ast = esprima.parse(source, {
+ comment: true,
+ loc: true,
+ range: true
+ });
+ } catch (e) {
+ e.message = 'Parse Error: ' + e.message;
+ throw e;
+ }
+ var state = utils.createState(source, ast, options);
+ state.g.visitors = visitors;
+
+ if (options.sourceMap) {
+ var SourceMapGenerator = require('source-map').SourceMapGenerator;
+ state.g.sourceMap = new SourceMapGenerator({file: 'transformed.js'});
+ }
+
+ traverse(ast, [], state);
+ utils.catchup(source.length, state);
+
+ var ret = {code: state.g.buffer};
+ if (options.sourceMap) {
+ ret.sourceMap = state.g.sourceMap;
+ ret.sourceMapFilename = options.filename || 'source.js';
+ }
+ return ret;
+}
+
+exports.transform = transform;
+
+},{"./utils":20,"esprima-fb":6,"source-map":8}],20:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*jslint node: true*/
+
+/**
+ * A `state` object represents the state of the parser. It has "local" and
+ * "global" parts. Global contains parser position, source, etc. Local contains
+ * scope based properties like current class name. State should contain all the
+ * info required for transformation. It's the only mandatory object that is
+ * being passed to every function in transform chain.
+ *
+ * @param {string} source
+ * @param {object} transformOptions
+ * @return {object}
+ */
+function createState(source, rootNode, transformOptions) {
+ return {
+ /**
+ * A tree representing the current local scope (and its lexical scope chain)
+ * Useful for tracking identifiers from parent scopes, etc.
+ * @type {Object}
+ */
+ localScope: {
+ parentNode: rootNode,
+ parentScope: null,
+ identifiers: {}
+ },
+ /**
+ * The name (and, if applicable, expression) of the super class
+ * @type {Object}
+ */
+ superClass: null,
+ /**
+ * The namespace to use when munging identifiers
+ * @type {String}
+ */
+ mungeNamespace: '',
+ /**
+ * Ref to the node for the FunctionExpression of the enclosing
+ * MethodDefinition
+ * @type {Object}
+ */
+ methodFuncNode: null,
+ /**
+ * Name of the enclosing class
+ * @type {String}
+ */
+ className: null,
+ /**
+ * Whether we're currently within a `strict` scope
+ * @type {Bool}
+ */
+ scopeIsStrict: null,
+ /**
+ * Global state (not affected by updateState)
+ * @type {Object}
+ */
+ g: {
+ /**
+ * A set of general options that transformations can consider while doing
+ * a transformation:
+ *
+ * - minify
+ * Specifies that transformation steps should do their best to minify
+ * the output source when possible. This is useful for places where
+ * minification optimizations are possible with higher-level context
+ * info than what jsxmin can provide.
+ *
+ * For example, the ES6 class transform will minify munged private
+ * variables if this flag is set.
+ */
+ opts: transformOptions,
+ /**
+ * Current position in the source code
+ * @type {Number}
+ */
+ position: 0,
+ /**
+ * Buffer containing the result
+ * @type {String}
+ */
+ buffer: '',
+ /**
+ * Indentation offset (only negative offset is supported now)
+ * @type {Number}
+ */
+ indentBy: 0,
+ /**
+ * Source that is being transformed
+ * @type {String}
+ */
+ source: source,
+
+ /**
+ * Cached parsed docblock (see getDocblock)
+ * @type {object}
+ */
+ docblock: null,
+
+ /**
+ * Whether the thing was used
+ * @type {Boolean}
+ */
+ tagNamespaceUsed: false,
+
+ /**
+ * If using bolt xjs transformation
+ * @type {Boolean}
+ */
+ isBolt: undefined,
+
+ /**
+ * Whether to record source map (expensive) or not
+ * @type {SourceMapGenerator|null}
+ */
+ sourceMap: null,
+
+ /**
+ * Filename of the file being processed. Will be returned as a source
+ * attribute in the source map
+ */
+ sourceMapFilename: 'source.js',
+
+ /**
+ * Only when source map is used: last line in the source for which
+ * source map was generated
+ * @type {Number}
+ */
+ sourceLine: 1,
+
+ /**
+ * Only when source map is used: last line in the buffer for which
+ * source map was generated
+ * @type {Number}
+ */
+ bufferLine: 1,
+
+ /**
+ * The top-level Program AST for the original file.
+ */
+ originalProgramAST: null,
+
+ sourceColumn: 0,
+ bufferColumn: 0
+ }
+ };
+}
+
+/**
+ * Updates a copy of a given state with "update" and returns an updated state.
+ *
+ * @param {object} state
+ * @param {object} update
+ * @return {object}
+ */
+function updateState(state, update) {
+ var ret = Object.create(state);
+ Object.keys(update).forEach(function(updatedKey) {
+ ret[updatedKey] = update[updatedKey];
+ });
+ return ret;
+}
+
+/**
+ * Given a state fill the resulting buffer from the original source up to
+ * the end
+ *
+ * @param {number} end
+ * @param {object} state
+ * @param {?function} contentTransformer Optional callback to transform newly
+ * added content.
+ */
+function catchup(end, state, contentTransformer) {
+ if (end < state.g.position) {
+ // cannot move backwards
+ return;
+ }
+ var source = state.g.source.substring(state.g.position, end);
+ var transformed = updateIndent(source, state);
+ if (state.g.sourceMap && transformed) {
+ // record where we are
+ state.g.sourceMap.addMapping({
+ generated: { line: state.g.bufferLine, column: state.g.bufferColumn },
+ original: { line: state.g.sourceLine, column: state.g.sourceColumn },
+ source: state.g.sourceMapFilename
+ });
+
+ // record line breaks in transformed source
+ var sourceLines = source.split('\n');
+ var transformedLines = transformed.split('\n');
+ // Add line break mappings between last known mapping and the end of the
+ // added piece. So for the code piece
+ // (foo, bar);
+ // > var x = 2;
+ // > var b = 3;
+ // var c =
+ // only add lines marked with ">": 2, 3.
+ for (var i = 1; i < sourceLines.length - 1; i++) {
+ state.g.sourceMap.addMapping({
+ generated: { line: state.g.bufferLine, column: 0 },
+ original: { line: state.g.sourceLine, column: 0 },
+ source: state.g.sourceMapFilename
+ });
+ state.g.sourceLine++;
+ state.g.bufferLine++;
+ }
+ // offset for the last piece
+ if (sourceLines.length > 1) {
+ state.g.sourceLine++;
+ state.g.bufferLine++;
+ state.g.sourceColumn = 0;
+ state.g.bufferColumn = 0;
+ }
+ state.g.sourceColumn += sourceLines[sourceLines.length - 1].length;
+ state.g.bufferColumn +=
+ transformedLines[transformedLines.length - 1].length;
+ }
+ state.g.buffer +=
+ contentTransformer ? contentTransformer(transformed) : transformed;
+ state.g.position = end;
+}
+
+/**
+ * Removes all non-whitespace characters
+ */
+var reNonWhite = /(\S)/g;
+function stripNonWhite(value) {
+ return value.replace(reNonWhite, function() {
+ return '';
+ });
+}
+
+/**
+ * Catches up as `catchup` but removes all non-whitespace characters.
+ */
+function catchupWhiteSpace(end, state) {
+ catchup(end, state, stripNonWhite);
+}
+
+/**
+ * Removes all non-newline characters
+ */
+var reNonNewline = /[^\n]/g;
+function stripNonNewline(value) {
+ return value.replace(reNonNewline, function() {
+ return '';
+ });
+}
+
+/**
+ * Catches up as `catchup` but removes all non-newline characters.
+ *
+ * Equivalent to appending as many newlines as there are in the original source
+ * between the current position and `end`.
+ */
+function catchupNewlines(end, state) {
+ catchup(end, state, stripNonNewline);
+}
+
+
+/**
+ * Same as catchup but does not touch the buffer
+ *
+ * @param {number} end
+ * @param {object} state
+ */
+function move(end, state) {
+ // move the internal cursors
+ if (state.g.sourceMap) {
+ if (end < state.g.position) {
+ state.g.position = 0;
+ state.g.sourceLine = 1;
+ state.g.sourceColumn = 0;
+ }
+
+ var source = state.g.source.substring(state.g.position, end);
+ var sourceLines = source.split('\n');
+ if (sourceLines.length > 1) {
+ state.g.sourceLine += sourceLines.length - 1;
+ state.g.sourceColumn = 0;
+ }
+ state.g.sourceColumn += sourceLines[sourceLines.length - 1].length;
+ }
+ state.g.position = end;
+}
+
+/**
+ * Appends a string of text to the buffer
+ *
+ * @param {string} str
+ * @param {object} state
+ */
+function append(str, state) {
+ if (state.g.sourceMap && str) {
+ state.g.sourceMap.addMapping({
+ generated: { line: state.g.bufferLine, column: state.g.bufferColumn },
+ original: { line: state.g.sourceLine, column: state.g.sourceColumn },
+ source: state.g.sourceMapFilename
+ });
+ var transformedLines = str.split('\n');
+ if (transformedLines.length > 1) {
+ state.g.bufferLine += transformedLines.length - 1;
+ state.g.bufferColumn = 0;
+ }
+ state.g.bufferColumn +=
+ transformedLines[transformedLines.length - 1].length;
+ }
+ state.g.buffer += str;
+}
+
+/**
+ * Update indent using state.indentBy property. Indent is measured in
+ * double spaces. Updates a single line only.
+ *
+ * @param {string} str
+ * @param {object} state
+ * @return {string}
+ */
+function updateIndent(str, state) {
+ for (var i = 0; i < -state.g.indentBy; i++) {
+ str = str.replace(/(^|\n)( {2}|\t)/g, '$1');
+ }
+ return str;
+}
+
+/**
+ * Calculates indent from the beginning of the line until "start" or the first
+ * character before start.
+ * @example
+ * " foo.bar()"
+ * ^
+ * start
+ * indent will be 2
+ *
+ * @param {number} start
+ * @param {object} state
+ * @return {number}
+ */
+function indentBefore(start, state) {
+ var end = start;
+ start = start - 1;
+
+ while (start > 0 && state.g.source[start] != '\n') {
+ if (!state.g.source[start].match(/[ \t]/)) {
+ end = start;
+ }
+ start--;
+ }
+ return state.g.source.substring(start + 1, end);
+}
+
+function getDocblock(state) {
+ if (!state.g.docblock) {
+ var docblock = require('./docblock');
+ state.g.docblock =
+ docblock.parseAsObject(docblock.extract(state.g.source));
+ }
+ return state.g.docblock;
+}
+
+function identWithinLexicalScope(identName, state, stopBeforeNode) {
+ var currScope = state.localScope;
+ while (currScope) {
+ if (currScope.identifiers[identName] !== undefined) {
+ return true;
+ }
+
+ if (stopBeforeNode && currScope.parentNode === stopBeforeNode) {
+ break;
+ }
+
+ currScope = currScope.parentScope;
+ }
+ return false;
+}
+
+function identInLocalScope(identName, state) {
+ return state.localScope.identifiers[identName] !== undefined;
+}
+
+function declareIdentInLocalScope(identName, state) {
+ state.localScope.identifiers[identName] = true;
+}
+
+/**
+ * Apply the given analyzer function to the current node. If the analyzer
+ * doesn't return false, traverse each child of the current node using the given
+ * traverser function.
+ *
+ * @param {function} analyzer
+ * @param {function} traverser
+ * @param {object} node
+ * @param {function} visitor
+ * @param {array} path
+ * @param {object} state
+ */
+function analyzeAndTraverse(analyzer, traverser, node, path, state) {
+ var key, child;
+
+ if (node.type) {
+ if (analyzer(node, path, state) === false) {
+ return;
+ }
+ path.unshift(node);
+ }
+
+ for (key in node) {
+ // skip obviously wrong attributes
+ if (key === 'range' || key === 'loc') {
+ continue;
+ }
+ if (node.hasOwnProperty(key)) {
+ child = node[key];
+ if (typeof child === 'object' && child !== null) {
+ traverser(child, path, state);
+ }
+ }
+ }
+ node.type && path.shift();
+}
+
+/**
+ * Checks whether a node or any of its sub-nodes contains
+ * a syntactic construct of the passed type.
+ * @param {object} node - AST node to test.
+ * @param {string} type - node type to lookup.
+ */
+function containsChildOfType(node, type) {
+ var foundMatchingChild = false;
+ function nodeTypeAnalyzer(node) {
+ if (node.type === type) {
+ foundMatchingChild = true;
+ return false;
+ }
+ }
+ function nodeTypeTraverser(child, path, state) {
+ if (!foundMatchingChild) {
+ foundMatchingChild = containsChildOfType(child, type);
+ }
+ }
+ analyzeAndTraverse(
+ nodeTypeAnalyzer,
+ nodeTypeTraverser,
+ node,
+ []
+ );
+ return foundMatchingChild;
+}
+
+exports.append = append;
+exports.catchup = catchup;
+exports.catchupWhiteSpace = catchupWhiteSpace;
+exports.catchupNewlines = catchupNewlines;
+exports.containsChildOfType = containsChildOfType;
+exports.createState = createState;
+exports.declareIdentInLocalScope = declareIdentInLocalScope;
+exports.getDocblock = getDocblock;
+exports.identWithinLexicalScope = identWithinLexicalScope;
+exports.identInLocalScope = identInLocalScope;
+exports.indentBefore = indentBefore;
+exports.move = move;
+exports.updateIndent = updateIndent;
+exports.updateState = updateState;
+exports.analyzeAndTraverse = analyzeAndTraverse;
+
+},{"./docblock":18}],21:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*global exports:true*/
+
+/**
+ * Desugars ES6 Arrow functions to ES3 function expressions.
+ * If the function contains `this` expression -- automatically
+ * binds the funciton to current value of `this`.
+ *
+ * Single parameter, simple expression:
+ *
+ * [1, 2, 3].map(x => x * x);
+ *
+ * [1, 2, 3].map(function(x) { return x * x; });
+ *
+ * Several parameters, complex block:
+ *
+ * this.users.forEach((user, idx) => {
+ * return this.isActive(idx) && this.send(user);
+ * });
+ *
+ * this.users.forEach(function(user, idx) {
+ * return this.isActive(idx) && this.send(user);
+ * }.bind(this));
+ *
+ */
+var restParamVisitors = require('./es6-rest-param-visitors');
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('../src/utils');
+
+/**
+ * @public
+ */
+function visitArrowFunction(traverse, node, path, state) {
+ // Prologue.
+ utils.append('function', state);
+ renderParams(node, state);
+
+ // Skip arrow.
+ utils.catchupWhiteSpace(node.body.range[0], state);
+
+ var renderBody = node.body.type == Syntax.BlockStatement
+ ? renderStatementBody
+ : renderExpressionBody;
+
+ path.unshift(node);
+ renderBody(traverse, node, path, state);
+ path.shift();
+
+ // Bind the function only if `this` value is used
+ // inside it or inside any sub-expression.
+ if (utils.containsChildOfType(node.body, Syntax.ThisExpression)) {
+ utils.append('.bind(this)', state);
+ }
+
+ return false;
+}
+
+function renderParams(node, state) {
+ // To preserve inline typechecking directives, we
+ // distinguish between parens-free and paranthesized single param.
+ if (isParensFreeSingleParam(node, state) || !node.params.length) {
+ utils.append('(', state);
+ }
+ if (node.params.length !== 0) {
+ utils.catchup(node.params[node.params.length - 1].range[1], state);
+ }
+ utils.append(')', state);
+}
+
+function isParensFreeSingleParam(node, state) {
+ return node.params.length === 1 &&
+ state.g.source[state.g.position] !== '(';
+}
+
+function renderExpressionBody(traverse, node, path, state) {
+ // Wrap simple expression bodies into a block
+ // with explicit return statement.
+ utils.append('{', state);
+ if (node.rest) {
+ utils.append(
+ restParamVisitors.renderRestParamSetup(node),
+ state
+ );
+ }
+ utils.append('return ', state);
+ renderStatementBody(traverse, node, path, state);
+ utils.append(';}', state);
+}
+
+function renderStatementBody(traverse, node, path, state) {
+ traverse(node.body, path, state);
+ utils.catchup(node.body.range[1], state);
+}
+
+visitArrowFunction.test = function(node, path, state) {
+ return node.type === Syntax.ArrowFunctionExpression;
+};
+
+exports.visitorList = [
+ visitArrowFunction
+];
+
+
+},{"../src/utils":20,"./es6-rest-param-visitors":24,"esprima-fb":6}],22:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*jslint node:true*/
+
+/**
+ * @typechecks
+ */
+'use strict';
+
+var base62 = require('base62');
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('../src/utils');
+
+var SUPER_PROTO_IDENT_PREFIX = '____SuperProtoOf';
+
+var _anonClassUUIDCounter = 0;
+var _mungedSymbolMaps = {};
+
+/**
+ * Used to generate a unique class for use with code-gens for anonymous class
+ * expressions.
+ *
+ * @param {object} state
+ * @return {string}
+ */
+function _generateAnonymousClassName(state) {
+ var mungeNamespace = state.mungeNamespace || '';
+ return '____Class' + mungeNamespace + base62.encode(_anonClassUUIDCounter++);
+}
+
+/**
+ * Given an identifier name, munge it using the current state's mungeNamespace.
+ *
+ * @param {string} identName
+ * @param {object} state
+ * @return {string}
+ */
+function _getMungedName(identName, state) {
+ var mungeNamespace = state.mungeNamespace;
+ var shouldMinify = state.g.opts.minify;
+
+ if (shouldMinify) {
+ if (!_mungedSymbolMaps[mungeNamespace]) {
+ _mungedSymbolMaps[mungeNamespace] = {
+ symbolMap: {},
+ identUUIDCounter: 0
+ };
+ }
+
+ var symbolMap = _mungedSymbolMaps[mungeNamespace].symbolMap;
+ if (!symbolMap[identName]) {
+ symbolMap[identName] =
+ base62.encode(_mungedSymbolMaps[mungeNamespace].identUUIDCounter++);
+ }
+ identName = symbolMap[identName];
+ }
+ return '$' + mungeNamespace + identName;
+}
+
+/**
+ * Extracts super class information from a class node.
+ *
+ * Information includes name of the super class and/or the expression string
+ * (if extending from an expression)
+ *
+ * @param {object} node
+ * @param {object} state
+ * @return {object}
+ */
+function _getSuperClassInfo(node, state) {
+ var ret = {
+ name: null,
+ expression: null
+ };
+ if (node.superClass) {
+ if (node.superClass.type === Syntax.Identifier) {
+ ret.name = node.superClass.name;
+ } else {
+ // Extension from an expression
+ ret.name = _generateAnonymousClassName(state);
+ ret.expression = state.g.source.substring(
+ node.superClass.range[0],
+ node.superClass.range[1]
+ );
+ }
+ }
+ return ret;
+}
+
+/**
+ * Used with .filter() to find the constructor method in a list of
+ * MethodDefinition nodes.
+ *
+ * @param {object} classElement
+ * @return {boolean}
+ */
+function _isConstructorMethod(classElement) {
+ return classElement.type === Syntax.MethodDefinition &&
+ classElement.key.type === Syntax.Identifier &&
+ classElement.key.name === 'constructor';
+}
+
+/**
+ * @param {object} node
+ * @param {object} state
+ * @return {boolean}
+ */
+function _shouldMungeIdentifier(node, state) {
+ return (
+ !!state.methodFuncNode &&
+ !utils.getDocblock(state).hasOwnProperty('preventMunge') &&
+ /^_(?!_)/.test(node.name)
+ );
+}
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitClassMethod(traverse, node, path, state) {
+ utils.catchup(node.range[0], state);
+ path.unshift(node);
+ traverse(node.value, path, state);
+ path.shift();
+ return false;
+}
+visitClassMethod.test = function(node, path, state) {
+ return node.type === Syntax.MethodDefinition;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitClassFunctionExpression(traverse, node, path, state) {
+ var methodNode = path[0];
+
+ state = utils.updateState(state, {
+ methodFuncNode: node
+ });
+
+ if (methodNode.key.name === 'constructor') {
+ utils.append('function ' + state.className, state);
+ } else {
+ var methodName = methodNode.key.name;
+ if (_shouldMungeIdentifier(methodNode.key, state)) {
+ methodName = _getMungedName(methodName, state);
+ }
+
+ var prototypeOrStatic = methodNode["static"] ? '' : 'prototype.';
+ utils.append(
+ state.className + '.' + prototypeOrStatic + methodName + '=function',
+ state
+ );
+ }
+ utils.move(methodNode.key.range[1], state);
+
+ var params = node.params;
+ var paramName;
+ if (params.length > 0) {
+ for (var i = 0; i < params.length; i++) {
+ utils.catchup(node.params[i].range[0], state);
+ paramName = params[i].name;
+ if (_shouldMungeIdentifier(params[i], state)) {
+ paramName = _getMungedName(params[i].name, state);
+ }
+ utils.append(paramName, state);
+ utils.move(params[i].range[1], state);
+ }
+ } else {
+ utils.append('(', state);
+ }
+ utils.append(')', state);
+ utils.catchupWhiteSpace(node.body.range[0], state);
+ utils.append('{', state);
+ if (!state.scopeIsStrict) {
+ utils.append('"use strict";', state);
+ }
+ utils.move(node.body.range[0] + '{'.length, state);
+
+ path.unshift(node);
+ traverse(node.body, path, state);
+ path.shift();
+ utils.catchup(node.body.range[1], state);
+
+ if (methodNode.key.name !== 'constructor') {
+ utils.append(';', state);
+ }
+ return false;
+}
+visitClassFunctionExpression.test = function(node, path, state) {
+ return node.type === Syntax.FunctionExpression
+ && path[0].type === Syntax.MethodDefinition;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function _renderClassBody(traverse, node, path, state) {
+ var className = state.className;
+ var superClass = state.superClass;
+
+ // Set up prototype of constructor on same line as `extends` for line-number
+ // preservation. This relies on function-hoisting if a constructor function is
+ // defined in the class body.
+ if (superClass.name) {
+ // If the super class is an expression, we need to memoize the output of the
+ // expression into the generated class name variable and use that to refer
+ // to the super class going forward. Example:
+ //
+ // class Foo extends mixin(Bar, Baz) {}
+ // --transforms to--
+ // function Foo() {} var ____Class0Blah = mixin(Bar, Baz);
+ if (superClass.expression !== null) {
+ utils.append(
+ 'var ' + superClass.name + '=' + superClass.expression + ';',
+ state
+ );
+ }
+
+ var keyName = superClass.name + '____Key';
+ var keyNameDeclarator = '';
+ if (!utils.identWithinLexicalScope(keyName, state)) {
+ keyNameDeclarator = 'var ';
+ utils.declareIdentInLocalScope(keyName, state);
+ }
+ utils.append(
+ 'for(' + keyNameDeclarator + keyName + ' in ' + superClass.name + '){' +
+ 'if(' + superClass.name + '.hasOwnProperty(' + keyName + ')){' +
+ className + '[' + keyName + ']=' +
+ superClass.name + '[' + keyName + '];' +
+ '}' +
+ '}',
+ state
+ );
+
+ var superProtoIdentStr = SUPER_PROTO_IDENT_PREFIX + superClass.name;
+ if (!utils.identWithinLexicalScope(superProtoIdentStr, state)) {
+ utils.append(
+ 'var ' + superProtoIdentStr + '=' + superClass.name + '===null?' +
+ 'null:' + superClass.name + '.prototype;',
+ state
+ );
+ utils.declareIdentInLocalScope(superProtoIdentStr, state);
+ }
+
+ utils.append(
+ className + '.prototype=Object.create(' + superProtoIdentStr + ');',
+ state
+ );
+ utils.append(
+ className + '.prototype.constructor=' + className + ';',
+ state
+ );
+ utils.append(
+ className + '.__superConstructor__=' + superClass.name + ';',
+ state
+ );
+ }
+
+ // If there's no constructor method specified in the class body, create an
+ // empty constructor function at the top (same line as the class keyword)
+ if (!node.body.body.filter(_isConstructorMethod).pop()) {
+ utils.append('function ' + className + '(){', state);
+ if (!state.scopeIsStrict) {
+ utils.append('"use strict";', state);
+ }
+ if (superClass.name) {
+ utils.append(
+ 'if(' + superClass.name + '!==null){' +
+ superClass.name + '.apply(this,arguments);}',
+ state
+ );
+ }
+ utils.append('}', state);
+ }
+
+ utils.move(node.body.range[0] + '{'.length, state);
+ traverse(node.body, path, state);
+ utils.catchupWhiteSpace(node.range[1], state);
+}
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitClassDeclaration(traverse, node, path, state) {
+ var className = node.id.name;
+ var superClass = _getSuperClassInfo(node, state);
+
+ state = utils.updateState(state, {
+ mungeNamespace: className,
+ className: className,
+ superClass: superClass
+ });
+
+ _renderClassBody(traverse, node, path, state);
+
+ return false;
+}
+visitClassDeclaration.test = function(node, path, state) {
+ return node.type === Syntax.ClassDeclaration;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitClassExpression(traverse, node, path, state) {
+ var className = node.id && node.id.name || _generateAnonymousClassName(state);
+ var superClass = _getSuperClassInfo(node, state);
+
+ utils.append('(function(){', state);
+
+ state = utils.updateState(state, {
+ mungeNamespace: className,
+ className: className,
+ superClass: superClass
+ });
+
+ _renderClassBody(traverse, node, path, state);
+
+ utils.append('return ' + className + ';})()', state);
+ return false;
+}
+visitClassExpression.test = function(node, path, state) {
+ return node.type === Syntax.ClassExpression;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitPrivateIdentifier(traverse, node, path, state) {
+ utils.append(_getMungedName(node.name, state), state);
+ utils.move(node.range[1], state);
+}
+visitPrivateIdentifier.test = function(node, path, state) {
+ if (node.type === Syntax.Identifier && _shouldMungeIdentifier(node, state)) {
+ // Always munge non-computed properties of MemberExpressions
+ // (a la preventing access of properties of unowned objects)
+ if (path[0].type === Syntax.MemberExpression && path[0].object !== node
+ && path[0].computed === false) {
+ return true;
+ }
+
+ // Always munge identifiers that were declared within the method function
+ // scope
+ if (utils.identWithinLexicalScope(node.name, state, state.methodFuncNode)) {
+ return true;
+ }
+
+ // Always munge private keys on object literals defined within a method's
+ // scope.
+ if (path[0].type === Syntax.Property
+ && path[1].type === Syntax.ObjectExpression) {
+ return true;
+ }
+
+ // Always munge function parameters
+ if (path[0].type === Syntax.FunctionExpression
+ || path[0].type === Syntax.FunctionDeclaration) {
+ for (var i = 0; i < path[0].params.length; i++) {
+ if (path[0].params[i] === node) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitSuperCallExpression(traverse, node, path, state) {
+ var superClassName = state.superClass.name;
+
+ if (node.callee.type === Syntax.Identifier) {
+ utils.append(superClassName + '.call(', state);
+ utils.move(node.callee.range[1], state);
+ } else if (node.callee.type === Syntax.MemberExpression) {
+ utils.append(SUPER_PROTO_IDENT_PREFIX + superClassName, state);
+ utils.move(node.callee.object.range[1], state);
+
+ if (node.callee.computed) {
+ // ["a" + "b"]
+ utils.catchup(node.callee.property.range[1] + ']'.length, state);
+ } else {
+ // .ab
+ utils.append('.' + node.callee.property.name, state);
+ }
+
+ utils.append('.call(', state);
+ utils.move(node.callee.range[1], state);
+ }
+
+ utils.append('this', state);
+ if (node.arguments.length > 0) {
+ utils.append(',', state);
+ utils.catchupWhiteSpace(node.arguments[0].range[0], state);
+ traverse(node.arguments, path, state);
+ }
+
+ utils.catchupWhiteSpace(node.range[1], state);
+ utils.append(')', state);
+ return false;
+}
+visitSuperCallExpression.test = function(node, path, state) {
+ if (state.superClass && node.type === Syntax.CallExpression) {
+ var callee = node.callee;
+ if (callee.type === Syntax.Identifier && callee.name === 'super'
+ || callee.type == Syntax.MemberExpression
+ && callee.object.name === 'super') {
+ return true;
+ }
+ }
+ return false;
+};
+
+/**
+ * @param {function} traverse
+ * @param {object} node
+ * @param {array} path
+ * @param {object} state
+ */
+function visitSuperMemberExpression(traverse, node, path, state) {
+ var superClassName = state.superClass.name;
+
+ utils.append(SUPER_PROTO_IDENT_PREFIX + superClassName, state);
+ utils.move(node.object.range[1], state);
+}
+visitSuperMemberExpression.test = function(node, path, state) {
+ return state.superClass
+ && node.type === Syntax.MemberExpression
+ && node.object.type === Syntax.Identifier
+ && node.object.name === 'super';
+};
+
+exports.visitorList = [
+ visitClassDeclaration,
+ visitClassExpression,
+ visitClassFunctionExpression,
+ visitClassMethod,
+ visitPrivateIdentifier,
+ visitSuperCallExpression,
+ visitSuperMemberExpression
+];
+
+},{"../src/utils":20,"base62":7,"esprima-fb":6}],23:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*jslint node: true*/
+
+/**
+ * Desugars ES6 Object Literal short notations into ES3 full notation.
+ *
+ * // Easier return values.
+ * function foo(x, y) {
+ * return {x, y}; // {x: x, y: y}
+ * };
+ *
+ * // Destrucruting.
+ * function init({port, ip, coords: {x, y}}) { ... }
+ *
+ */
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('../src/utils');
+
+/**
+ * @public
+ */
+function visitObjectLiteralShortNotation(traverse, node, path, state) {
+ utils.catchup(node.key.range[1], state);
+ utils.append(':' + node.key.name, state);
+ return false;
+}
+
+visitObjectLiteralShortNotation.test = function(node, path, state) {
+ return node.type === Syntax.Property &&
+ node.kind === 'init' &&
+ node.shorthand === true;
+};
+
+exports.visitorList = [
+ visitObjectLiteralShortNotation
+];
+
+
+},{"../src/utils":20,"esprima-fb":6}],24:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*jslint node:true*/
+
+/**
+ * Desugars ES6 rest parameters into ES3 arguments slicing.
+ *
+ * function printf(template, ...args) {
+ * args.forEach(...);
+ * };
+ *
+ * function printf(template) {
+ * var args = [].slice.call(arguments, 1);
+ * args.forEach(...);
+ * };
+ *
+ */
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('../src/utils');
+
+function _nodeIsFunctionWithRestParam(node) {
+ return (node.type === Syntax.FunctionDeclaration
+ || node.type === Syntax.FunctionExpression
+ || node.type === Syntax.ArrowFunctionExpression)
+ && node.rest;
+}
+
+function visitFunctionParamsWithRestParam(traverse, node, path, state) {
+ // Render params.
+ if (node.params.length) {
+ utils.catchup(node.params[node.params.length - 1].range[1], state);
+ } else {
+ // -3 is for ... of the rest.
+ utils.catchup(node.rest.range[0] - 3, state);
+ }
+ utils.catchupWhiteSpace(node.rest.range[1], state);
+}
+
+visitFunctionParamsWithRestParam.test = function(node, path, state) {
+ return _nodeIsFunctionWithRestParam(node);
+};
+
+function renderRestParamSetup(functionNode) {
+ return 'var ' + functionNode.rest.name + '=Array.prototype.slice.call(' +
+ 'arguments,' +
+ functionNode.params.length +
+ ');';
+}
+
+function visitFunctionBodyWithRestParam(traverse, node, path, state) {
+ utils.catchup(node.range[0] + 1, state);
+ var parentNode = path[0];
+ utils.append(renderRestParamSetup(parentNode), state);
+ traverse(node.body, path, state);
+ return false;
+}
+
+visitFunctionBodyWithRestParam.test = function(node, path, state) {
+ return node.type === Syntax.BlockStatement
+ && _nodeIsFunctionWithRestParam(path[0]);
+};
+
+exports.renderRestParamSetup = renderRestParamSetup;
+exports.visitorList = [
+ visitFunctionParamsWithRestParam,
+ visitFunctionBodyWithRestParam
+];
+
+},{"../src/utils":20,"esprima-fb":6}],25:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*jslint node:true*/
+
+/**
+ * @typechecks
+ */
+'use strict';
+
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('../src/utils');
+
+/**
+ * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.1.9
+ */
+function visitTemplateLiteral(traverse, node, path, state) {
+ var templateElements = node.quasis;
+
+ utils.append('(', state);
+ for (var ii = 0; ii < templateElements.length; ii++) {
+ var templateElement = templateElements[ii];
+ if (templateElement.value.raw !== '') {
+ utils.append(getCookedValue(templateElement), state);
+ if (!templateElement.tail) {
+ // + between element and substitution
+ utils.append(' + ', state);
+ }
+ // maintain line numbers
+ utils.move(templateElement.range[0], state);
+ utils.catchupNewlines(templateElement.range[1], state);
+ }
+ utils.move(templateElement.range[1], state);
+ if (!templateElement.tail) {
+ var substitution = node.expressions[ii];
+ if (substitution.type === Syntax.Identifier ||
+ substitution.type === Syntax.MemberExpression ||
+ substitution.type === Syntax.CallExpression) {
+ utils.catchup(substitution.range[1], state);
+ } else {
+ utils.append('(', state);
+ traverse(substitution, path, state);
+ utils.catchup(substitution.range[1], state);
+ utils.append(')', state);
+ }
+ // if next templateElement isn't empty...
+ if (templateElements[ii + 1].value.cooked !== '') {
+ utils.append(' + ', state);
+ }
+ }
+ }
+ utils.move(node.range[1], state);
+ utils.append(')', state);
+ return false;
+}
+
+visitTemplateLiteral.test = function(node, path, state) {
+ return node.type === Syntax.TemplateLiteral;
+};
+
+/**
+ * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.2.6
+ */
+function visitTaggedTemplateExpression(traverse, node, path, state) {
+ var template = node.quasi;
+ var numQuasis = template.quasis.length;
+
+ // print the tag
+ utils.move(node.tag.range[0], state);
+ traverse(node.tag, path, state);
+ utils.catchup(node.tag.range[1], state);
+
+ // print array of template elements
+ utils.append('(function() { var siteObj = [', state);
+ for (var ii = 0; ii < numQuasis; ii++) {
+ utils.append(getCookedValue(template.quasis[ii]), state);
+ if (ii !== numQuasis - 1) {
+ utils.append(', ', state);
+ }
+ }
+ utils.append(']; siteObj.raw = [', state);
+ for (ii = 0; ii < numQuasis; ii++) {
+ utils.append(getRawValue(template.quasis[ii]), state);
+ if (ii !== numQuasis - 1) {
+ utils.append(', ', state);
+ }
+ }
+ utils.append(
+ ']; Object.freeze(siteObj.raw); Object.freeze(siteObj); return siteObj; }()',
+ state
+ );
+
+ // print substitutions
+ if (numQuasis > 1) {
+ for (ii = 0; ii < template.expressions.length; ii++) {
+ var expression = template.expressions[ii];
+ utils.append(', ', state);
+
+ // maintain line numbers by calling catchupWhiteSpace over the whole
+ // previous TemplateElement
+ utils.move(template.quasis[ii].range[0], state);
+ utils.catchupNewlines(template.quasis[ii].range[1], state);
+
+ utils.move(expression.range[0], state);
+ traverse(expression, path, state);
+ utils.catchup(expression.range[1], state);
+ }
+ }
+
+ // print blank lines to push the closing ) down to account for the final
+ // TemplateElement.
+ utils.catchupNewlines(node.range[1], state);
+
+ utils.append(')', state);
+
+ return false;
+}
+
+visitTaggedTemplateExpression.test = function(node, path, state) {
+ return node.type === Syntax.TaggedTemplateExpression;
+};
+
+function getCookedValue(templateElement) {
+ return JSON.stringify(templateElement.value.cooked);
+}
+
+function getRawValue(templateElement) {
+ return JSON.stringify(templateElement.value.raw);
+}
+
+exports.visitorList = [
+ visitTemplateLiteral,
+ visitTaggedTemplateExpression
+];
+
+},{"../src/utils":20,"esprima-fb":6}],26:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* jshint browser: true */
+/* jslint evil: true */
+
+'use strict';
+var runScripts;
+var headEl;
+
+var buffer = require('buffer');
+var transform = require('jstransform').transform;
+var visitors = require('./fbtransform/visitors').transformVisitors;
+var docblock = require('jstransform/src/docblock');
+
+// The source-map library relies on Object.defineProperty, but IE8 doesn't
+// support it fully even with es5-sham. Indeed, es5-sham's defineProperty
+// throws when Object.prototype.__defineGetter__ is missing, so we skip building
+// the source map in that case.
+var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
+
+function transformReact(source) {
+ return transform(visitors.react, source, {
+ sourceMap: supportsAccessors
+ });
+}
+
+exports.transform = transformReact;
+
+exports.exec = function(code) {
+ return eval(transformReact(code).code);
+};
+
+var inlineScriptCount = 0;
+
+// This method returns a nicely formated line of code pointing the
+// exactly location of the error `e`.
+// The line is limited in size so big lines of code are also shown
+// in a readable way.
+// Example:
+//
+// ... x', overflow:'scroll'}} id={} onScroll={this.scroll} class=" ...
+// ^
+var createSourceCodeErrorMessage = function(code, e) {
+ var sourceLines = code.split('\n');
+ var erroneousLine = sourceLines[e.lineNumber - 1];
+
+ // Removes any leading indenting spaces and gets the number of
+ // chars indenting the `erroneousLine`
+ var indentation = 0;
+ erroneousLine = erroneousLine.replace(/^\s+/, function(leadingSpaces) {
+ indentation = leadingSpaces.length;
+ return '';
+ });
+
+ // Defines the number of characters that are going to show
+ // before and after the erroneous code
+ var LIMIT = 30;
+ var errorColumn = e.column - indentation;
+
+ if (errorColumn > LIMIT) {
+ erroneousLine = '... ' + erroneousLine.slice(errorColumn - LIMIT);
+ errorColumn = 4 + LIMIT;
+ }
+ if (erroneousLine.length - errorColumn > LIMIT) {
+ erroneousLine = erroneousLine.slice(0, errorColumn + LIMIT) + ' ...';
+ }
+ var message = '\n\n' + erroneousLine + '\n';
+ message += new Array(errorColumn - 1).join(' ') + '^';
+ return message;
+};
+
+var transformCode = function(code, source) {
+ var jsx = docblock.parseAsObject(docblock.extract(code)).jsx;
+
+ if (jsx) {
+ try {
+ var transformed = transformReact(code);
+ } catch(e) {
+ e.message += '\n at ';
+ if (source) {
+ if ('fileName' in e) {
+ // We set `fileName` if it's supported by this error object and
+ // a `source` was provided.
+ // The error will correctly point to `source` in Firefox.
+ e.fileName = source;
+ }
+ e.message += source + ':' + e.lineNumber + ':' + e.column;
+ } else {
+ e.message += location.href;
+ }
+ e.message += createSourceCodeErrorMessage(code, e);
+ throw e;
+ }
+
+ if (!transformed.sourceMap) {
+ return transformed.code;
+ }
+
+ var map = transformed.sourceMap.toJSON();
+ if (source == null) {
+ source = "Inline JSX script";
+ inlineScriptCount++;
+ if (inlineScriptCount > 1) {
+ source += ' (' + inlineScriptCount + ')';
+ }
+ }
+ map.sources = [source];
+ map.sourcesContent = [code];
+
+ return (
+ transformed.code +
+ '//# sourceMappingURL=data:application/json;base64,' +
+ buffer.Buffer(JSON.stringify(map)).toString('base64')
+ );
+ } else {
+ return code;
+ }
+};
+
+var run = exports.run = function(code, source) {
+ var scriptEl = document.createElement('script');
+ scriptEl.text = transformCode(code, source);
+ headEl.appendChild(scriptEl);
+};
+
+var load = exports.load = function(url, callback) {
+ var xhr;
+ xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP')
+ : new XMLHttpRequest();
+
+ // Disable async since we need to execute scripts in the order they are in the
+ // DOM to mirror normal script loading.
+ xhr.open('GET', url, false);
+ if ('overrideMimeType' in xhr) {
+ xhr.overrideMimeType('text/plain');
+ }
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 0 || xhr.status === 200) {
+ run(xhr.responseText, url);
+ } else {
+ throw new Error("Could not load " + url);
+ }
+ if (callback) {
+ return callback();
+ }
+ }
+ };
+ return xhr.send(null);
+};
+
+runScripts = function() {
+ var scripts = document.getElementsByTagName('script');
+
+ // Array.prototype.slice cannot be used on NodeList on IE8
+ var jsxScripts = [];
+ for (var i = 0; i < scripts.length; i++) {
+ if (scripts.item(i).type === 'text/jsx') {
+ jsxScripts.push(scripts.item(i));
+ }
+ }
+
+ console.warn("You are using the in-browser JSX transformer. Be sure to precompile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx");
+
+ jsxScripts.forEach(function(script) {
+ if (script.src) {
+ load(script.src);
+ } else {
+ run(script.innerHTML, null);
+ }
+ });
+};
+
+if (typeof window !== "undefined" && window !== null) {
+ headEl = document.getElementsByTagName('head')[0];
+
+ if (window.addEventListener) {
+ window.addEventListener('DOMContentLoaded', runScripts, false);
+ } else {
+ window.attachEvent('onload', runScripts);
+ }
+}
+
+},{"./fbtransform/visitors":30,"buffer":2,"jstransform":19,"jstransform/src/docblock":18}],27:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*global exports:true*/
+"use strict";
+
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('jstransform/src/utils');
+
+var FALLBACK_TAGS = require('./xjs').knownTags;
+var renderXJSExpressionContainer =
+ require('./xjs').renderXJSExpressionContainer;
+var renderXJSLiteral = require('./xjs').renderXJSLiteral;
+var quoteAttrName = require('./xjs').quoteAttrName;
+
+/**
+ * Customized desugar processor.
+ *
+ * Currently: (Somewhat tailored to React)
+ * => X(null, null)
+ * => X({prop: '1'}, null)
+ * => X({prop:'2'}, Y(null, null))
+ * => X({prop:'2'}, [Y(null, null), Z(null, null)])
+ *
+ * Exceptions to the simple rules above:
+ * if a property is named "class" it will be changed to "className" in the
+ * javascript since "class" is not a valid object key in javascript.
+ */
+
+var JSX_ATTRIBUTE_TRANSFORMS = {
+ cxName: function(attr) {
+ throw new Error(
+ "cxName is no longer supported, use className={cx(...)} instead"
+ );
+ }
+};
+
+function visitReactTag(traverse, object, path, state) {
+ var jsxObjIdent = utils.getDocblock(state).jsx;
+ var openingElement = object.openingElement;
+ var nameObject = openingElement.name;
+ var attributesObject = openingElement.attributes;
+
+ utils.catchup(openingElement.range[0], state);
+
+ if (nameObject.namespace) {
+ throw new Error(
+ 'Namespace tags are not supported. ReactJSX is not XML.');
+ }
+
+ var isFallbackTag = FALLBACK_TAGS[nameObject.name];
+ utils.append(
+ (isFallbackTag ? jsxObjIdent + '.' : '') + (nameObject.name) + '(',
+ state
+ );
+
+ utils.move(nameObject.range[1], state);
+
+ // if we don't have any attributes, pass in null
+ if (attributesObject.length === 0) {
+ utils.append('null', state);
+ }
+
+ // write attributes
+ attributesObject.forEach(function(attr, index) {
+ utils.catchup(attr.range[0], state);
+ if (attr.name.namespace) {
+ throw new Error(
+ 'Namespace attributes are not supported. ReactJSX is not XML.');
+ }
+ var name = attr.name.name;
+ var isFirst = index === 0;
+ var isLast = index === attributesObject.length - 1;
+
+ if (isFirst) {
+ utils.append('{', state);
+ }
+
+ utils.append(quoteAttrName(name), state);
+ utils.append(':', state);
+
+ if (!attr.value) {
+ state.g.buffer += 'true';
+ state.g.position = attr.name.range[1];
+ if (!isLast) {
+ utils.append(',', state);
+ }
+ } else {
+ utils.move(attr.name.range[1], state);
+ // Use catchupWhiteSpace to skip over the '=' in the attribute
+ utils.catchupWhiteSpace(attr.value.range[0], state);
+ if (JSX_ATTRIBUTE_TRANSFORMS[attr.name.name]) {
+ utils.append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state);
+ utils.move(attr.value.range[1], state);
+ if (!isLast) {
+ utils.append(',', state);
+ }
+ } else if (attr.value.type === Syntax.Literal) {
+ renderXJSLiteral(attr.value, isLast, state);
+ } else {
+ renderXJSExpressionContainer(traverse, attr.value, isLast, path, state);
+ }
+ }
+
+ if (isLast) {
+ utils.append('}', state);
+ }
+
+ utils.catchup(attr.range[1], state);
+ });
+
+ if (!openingElement.selfClosing) {
+ utils.catchup(openingElement.range[1] - 1, state);
+ utils.move(openingElement.range[1], state);
+ }
+
+ // filter out whitespace
+ var childrenToRender = object.children.filter(function(child) {
+ return !(child.type === Syntax.Literal
+ && typeof child.value === 'string'
+ && child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/));
+ });
+ if (childrenToRender.length > 0) {
+ utils.append(', ', state);
+
+ childrenToRender.forEach(function(child, index) {
+ utils.catchup(child.range[0], state);
+
+ var isLast = index === childrenToRender.length - 1;
+
+ if (child.type === Syntax.Literal) {
+ renderXJSLiteral(child, isLast, state);
+ } else if (child.type === Syntax.XJSExpressionContainer) {
+ renderXJSExpressionContainer(traverse, child, isLast, path, state);
+ } else {
+ traverse(child, path, state);
+ if (!isLast) {
+ utils.append(',', state);
+ state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1');
+ }
+ }
+
+ utils.catchup(child.range[1], state);
+ });
+ }
+
+ if (openingElement.selfClosing) {
+ // everything up to />
+ utils.catchup(openingElement.range[1] - 2, state);
+ utils.move(openingElement.range[1], state);
+ } else {
+ // everything up to sdflksjfd>
+ utils.catchup(object.closingElement.range[0], state);
+ utils.move(object.closingElement.range[1], state);
+ }
+
+ utils.append(')', state);
+ return false;
+}
+
+visitReactTag.test = function(object, path, state) {
+ // only run react when react @jsx namespace is specified in docblock
+ var jsx = utils.getDocblock(state).jsx;
+ return object.type === Syntax.XJSElement && jsx && jsx.length;
+};
+
+exports.visitorList = [
+ visitReactTag
+];
+
+},{"./xjs":29,"esprima-fb":6,"jstransform/src/utils":20}],28:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*global exports:true*/
+"use strict";
+
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('jstransform/src/utils');
+
+function addDisplayName(displayName, object, state) {
+ if (object &&
+ object.type === Syntax.CallExpression &&
+ object.callee.type === Syntax.MemberExpression &&
+ object.callee.object.type === Syntax.Identifier &&
+ object.callee.object.name === 'React' &&
+ object.callee.property.type === Syntax.Identifier &&
+ object.callee.property.name === 'createClass' &&
+ object['arguments'].length === 1 &&
+ object['arguments'][0].type === Syntax.ObjectExpression) {
+ // Verify that the displayName property isn't already set
+ var properties = object['arguments'][0].properties;
+ var safe = properties.every(function(property) {
+ var value = property.key.type === Syntax.Identifier ?
+ property.key.name :
+ property.key.value;
+ return value !== 'displayName';
+ });
+
+ if (safe) {
+ utils.catchup(object['arguments'][0].range[0] + 1, state);
+ utils.append("displayName: '" + displayName + "',", state);
+ }
+ }
+}
+
+/**
+ * Transforms the following:
+ *
+ * var MyComponent = React.createClass({
+ * render: ...
+ * });
+ *
+ * into:
+ *
+ * var MyComponent = React.createClass({
+ * displayName: 'MyComponent',
+ * render: ...
+ * });
+ *
+ * Also catches:
+ *
+ * MyComponent = React.createClass(...);
+ * exports.MyComponent = React.createClass(...);
+ * module.exports = {MyComponent: React.createClass(...)};
+ */
+function visitReactDisplayName(traverse, object, path, state) {
+ var left, right;
+
+ if (object.type === Syntax.AssignmentExpression) {
+ left = object.left;
+ right = object.right;
+ } else if (object.type === Syntax.Property) {
+ left = object.key;
+ right = object.value;
+ } else if (object.type === Syntax.VariableDeclarator) {
+ left = object.id;
+ right = object.init;
+ }
+
+ if (left && left.type === Syntax.MemberExpression) {
+ left = left.property;
+ }
+ if (left && left.type === Syntax.Identifier) {
+ addDisplayName(left.name, right, state);
+ }
+}
+
+/**
+ * Will only run on @jsx files for now.
+ */
+visitReactDisplayName.test = function(object, path, state) {
+ if (utils.getDocblock(state).jsx) {
+ return (
+ object.type === Syntax.AssignmentExpression ||
+ object.type === Syntax.Property ||
+ object.type === Syntax.VariableDeclarator
+ );
+ } else {
+ return false;
+ }
+};
+
+exports.visitorList = [
+ visitReactDisplayName
+];
+
+},{"esprima-fb":6,"jstransform/src/utils":20}],29:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*global exports:true*/
+"use strict";
+var Syntax = require('esprima-fb').Syntax;
+var utils = require('jstransform/src/utils');
+
+var knownTags = {
+ a: true,
+ abbr: true,
+ address: true,
+ applet: true,
+ area: true,
+ article: true,
+ aside: true,
+ audio: true,
+ b: true,
+ base: true,
+ bdi: true,
+ bdo: true,
+ big: true,
+ blockquote: true,
+ body: true,
+ br: true,
+ button: true,
+ canvas: true,
+ caption: true,
+ circle: true,
+ cite: true,
+ code: true,
+ col: true,
+ colgroup: true,
+ command: true,
+ data: true,
+ datalist: true,
+ dd: true,
+ defs: true,
+ del: true,
+ details: true,
+ dfn: true,
+ dialog: true,
+ div: true,
+ dl: true,
+ dt: true,
+ ellipse: true,
+ em: true,
+ embed: true,
+ fieldset: true,
+ figcaption: true,
+ figure: true,
+ footer: true,
+ form: true,
+ g: true,
+ h1: true,
+ h2: true,
+ h3: true,
+ h4: true,
+ h5: true,
+ h6: true,
+ head: true,
+ header: true,
+ hgroup: true,
+ hr: true,
+ html: true,
+ i: true,
+ iframe: true,
+ img: true,
+ input: true,
+ ins: true,
+ kbd: true,
+ keygen: true,
+ label: true,
+ legend: true,
+ li: true,
+ line: true,
+ linearGradient: true,
+ link: true,
+ main: true,
+ map: true,
+ mark: true,
+ marquee: true,
+ menu: true,
+ menuitem: true,
+ meta: true,
+ meter: true,
+ nav: true,
+ noscript: true,
+ object: true,
+ ol: true,
+ optgroup: true,
+ option: true,
+ output: true,
+ p: true,
+ param: true,
+ path: true,
+ polyline: true,
+ pre: true,
+ progress: true,
+ q: true,
+ radialGradient: true,
+ rect: true,
+ rp: true,
+ rt: true,
+ ruby: true,
+ s: true,
+ samp: true,
+ script: true,
+ section: true,
+ select: true,
+ small: true,
+ source: true,
+ span: true,
+ stop: true,
+ strong: true,
+ style: true,
+ sub: true,
+ summary: true,
+ sup: true,
+ svg: true,
+ table: true,
+ tbody: true,
+ td: true,
+ text: true,
+ textarea: true,
+ tfoot: true,
+ th: true,
+ thead: true,
+ time: true,
+ title: true,
+ tr: true,
+ track: true,
+ u: true,
+ ul: true,
+ 'var': true,
+ video: true,
+ wbr: true
+};
+
+function renderXJSLiteral(object, isLast, state, start, end) {
+ var lines = object.value.split(/\r\n|\n|\r/);
+
+ if (start) {
+ utils.append(start, state);
+ }
+
+ var lastNonEmptyLine = 0;
+
+ lines.forEach(function (line, index) {
+ if (line.match(/[^ \t]/)) {
+ lastNonEmptyLine = index;
+ }
+ });
+
+ lines.forEach(function (line, index) {
+ var isFirstLine = index === 0;
+ var isLastLine = index === lines.length - 1;
+ var isLastNonEmptyLine = index === lastNonEmptyLine;
+
+ // replace rendered whitespace tabs with spaces
+ var trimmedLine = line.replace(/\t/g, ' ');
+
+ // trim whitespace touching a newline
+ if (!isFirstLine) {
+ trimmedLine = trimmedLine.replace(/^[ ]+/, '');
+ }
+ if (!isLastLine) {
+ trimmedLine = trimmedLine.replace(/[ ]+$/, '');
+ }
+
+ utils.append(line.match(/^[ \t]*/)[0], state);
+
+ if (trimmedLine || isLastNonEmptyLine) {
+ utils.append(
+ JSON.stringify(trimmedLine) +
+ (!isLastNonEmptyLine ? "+' '+" : ''),
+ state);
+
+ if (isLastNonEmptyLine) {
+ if (end) {
+ utils.append(end, state);
+ }
+ if (!isLast) {
+ utils.append(',', state);
+ }
+ }
+
+ // only restore tail whitespace if line had literals
+ if (trimmedLine) {
+ utils.append(line.match(/[ \t]*$/)[0], state);
+ }
+ }
+
+ if (!isLastLine) {
+ utils.append('\n', state);
+ }
+ });
+
+ utils.move(object.range[1], state);
+}
+
+function renderXJSExpressionContainer(traverse, object, isLast, path, state) {
+ // Plus 1 to skip `{`.
+ utils.move(object.range[0] + 1, state);
+ traverse(object.expression, path, state);
+ if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) {
+ // If we need to append a comma, make sure to do so after the expression.
+ utils.catchup(object.expression.range[1], state);
+ utils.append(',', state);
+ }
+
+ // Minus 1 to skip `}`.
+ utils.catchup(object.range[1] - 1, state);
+ utils.move(object.range[1], state);
+ return false;
+}
+
+function quoteAttrName(attr) {
+ // Quote invalid JS identifiers.
+ if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) {
+ return "'" + attr + "'";
+ }
+ return attr;
+}
+
+exports.knownTags = knownTags;
+exports.renderXJSExpressionContainer = renderXJSExpressionContainer;
+exports.renderXJSLiteral = renderXJSLiteral;
+exports.quoteAttrName = quoteAttrName;
+
+},{"esprima-fb":6,"jstransform/src/utils":20}],30:[function(require,module,exports){
+/*global exports:true*/
+var es6ArrowFunctions = require('jstransform/visitors/es6-arrow-function-visitors');
+var es6Classes = require('jstransform/visitors/es6-class-visitors');
+var es6ObjectShortNotation = require('jstransform/visitors/es6-object-short-notation-visitors');
+var es6RestParameters = require('jstransform/visitors/es6-rest-param-visitors');
+var es6Templates = require('jstransform/visitors/es6-template-visitors');
+var react = require('./transforms/react');
+var reactDisplayName = require('./transforms/reactDisplayName');
+
+/**
+ * Map from transformName => orderedListOfVisitors.
+ */
+var transformVisitors = {
+ 'es6-arrow-functions': es6ArrowFunctions.visitorList,
+ 'es6-classes': es6Classes.visitorList,
+ 'es6-object-short-notation': es6ObjectShortNotation.visitorList,
+ 'es6-rest-params': es6RestParameters.visitorList,
+ 'es6-templates': es6Templates.visitorList,
+ 'react': react.visitorList.concat(reactDisplayName.visitorList)
+};
+
+/**
+ * Specifies the order in which each transform should run.
+ */
+var transformRunOrder = [
+ 'es6-arrow-functions',
+ 'es6-object-short-notation',
+ 'es6-classes',
+ 'es6-rest-params',
+ 'es6-templates',
+ 'react'
+];
+
+/**
+ * Given a list of transform names, return the ordered list of visitors to be
+ * passed to the transform() function.
+ *
+ * @param {array?} excludes
+ * @return {array}
+ */
+function getAllVisitors(excludes) {
+ var ret = [];
+ for (var i = 0, il = transformRunOrder.length; i < il; i++) {
+ if (!excludes || excludes.indexOf(transformRunOrder[i]) === -1) {
+ ret = ret.concat(transformVisitors[transformRunOrder[i]]);
+ }
+ }
+ return ret;
+}
+
+exports.getAllVisitors = getAllVisitors;
+exports.transformVisitors = transformVisitors;
+
+},{"./transforms/react":27,"./transforms/reactDisplayName":28,"jstransform/visitors/es6-arrow-function-visitors":21,"jstransform/visitors/es6-class-visitors":22,"jstransform/visitors/es6-object-short-notation-visitors":23,"jstransform/visitors/es6-rest-param-visitors":24,"jstransform/visitors/es6-template-visitors":25}]},{},[26])
+(26)
+});
\ No newline at end of file
diff --git a/vendor/react/bower.json b/vendor/react/bower.json
new file mode 100644
index 0000000..3585b5e
--- /dev/null
+++ b/vendor/react/bower.json
@@ -0,0 +1,5 @@
+{
+ "name": "react",
+ "version": "0.9.0",
+ "main": "react.js"
+}
\ No newline at end of file
diff --git a/vendor/react/react-with-addons.js b/vendor/react/react-with-addons.js
new file mode 100644
index 0000000..175bab8
--- /dev/null
+++ b/vendor/react/react-with-addons.js
@@ -0,0 +1,18137 @@
+/**
+ * React (with addons) v0.9.0
+ */
+!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.React=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1;
+ }
+
+};
+
+module.exports = CSSCore;
+
+},{"./invariant":121}],3:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule CSSProperty
+ */
+
+"use strict";
+
+/**
+ * CSS properties which accept numbers but are not in units of "px".
+ */
+var isUnitlessNumber = {
+ columnCount: true,
+ fillOpacity: true,
+ flex: true,
+ flexGrow: true,
+ flexShrink: true,
+ fontWeight: true,
+ lineClamp: true,
+ lineHeight: true,
+ opacity: true,
+ order: true,
+ orphans: true,
+ widows: true,
+ zIndex: true,
+ zoom: true
+};
+
+/**
+ * @param {string} prefix vendor-specific prefix, eg: Webkit
+ * @param {string} key style name, eg: transitionDuration
+ * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
+ * WebkitTransitionDuration
+ */
+function prefixKey(prefix, key) {
+ return prefix + key.charAt(0).toUpperCase() + key.substring(1);
+}
+
+/**
+ * Support style names that may come passed in prefixed by adding permutations
+ * of vendor prefixes.
+ */
+var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
+
+// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
+// infinite loop, because it iterates over the newly added props too.
+Object.keys(isUnitlessNumber).forEach(function(prop) {
+ prefixes.forEach(function(prefix) {
+ isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
+ });
+});
+
+/**
+ * Most style properties can be unset by doing .style[prop] = '' but IE8
+ * doesn't like doing that with shorthand properties so for the properties that
+ * IE8 breaks on, which are listed here, we instead unset each of the
+ * individual properties. See http://bugs.jquery.com/ticket/12385.
+ * The 4-value 'clock' properties like margin, padding, border-width seem to
+ * behave without any problems. Curiously, list-style works too without any
+ * special prodding.
+ */
+var shorthandPropertyExpansions = {
+ background: {
+ backgroundImage: true,
+ backgroundPosition: true,
+ backgroundRepeat: true,
+ backgroundColor: true
+ },
+ border: {
+ borderWidth: true,
+ borderStyle: true,
+ borderColor: true
+ },
+ borderBottom: {
+ borderBottomWidth: true,
+ borderBottomStyle: true,
+ borderBottomColor: true
+ },
+ borderLeft: {
+ borderLeftWidth: true,
+ borderLeftStyle: true,
+ borderLeftColor: true
+ },
+ borderRight: {
+ borderRightWidth: true,
+ borderRightStyle: true,
+ borderRightColor: true
+ },
+ borderTop: {
+ borderTopWidth: true,
+ borderTopStyle: true,
+ borderTopColor: true
+ },
+ font: {
+ fontStyle: true,
+ fontVariant: true,
+ fontWeight: true,
+ fontSize: true,
+ lineHeight: true,
+ fontFamily: true
+ }
+};
+
+var CSSProperty = {
+ isUnitlessNumber: isUnitlessNumber,
+ shorthandPropertyExpansions: shorthandPropertyExpansions
+};
+
+module.exports = CSSProperty;
+
+},{}],4:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule CSSPropertyOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var CSSProperty = require("./CSSProperty");
+
+var dangerousStyleValue = require("./dangerousStyleValue");
+var escapeTextForBrowser = require("./escapeTextForBrowser");
+var hyphenate = require("./hyphenate");
+var memoizeStringOnly = require("./memoizeStringOnly");
+
+var processStyleName = memoizeStringOnly(function(styleName) {
+ return escapeTextForBrowser(hyphenate(styleName));
+});
+
+/**
+ * Operations for dealing with CSS properties.
+ */
+var CSSPropertyOperations = {
+
+ /**
+ * Serializes a mapping of style properties for use as inline styles:
+ *
+ * > createMarkupForStyles({width: '200px', height: 0})
+ * "width:200px;height:0;"
+ *
+ * Undefined values are ignored so that declarative programming is easier.
+ *
+ * @param {object} styles
+ * @return {?string}
+ */
+ createMarkupForStyles: function(styles) {
+ var serialized = '';
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ var styleValue = styles[styleName];
+ if (styleValue != null) {
+ serialized += processStyleName(styleName) + ':';
+ serialized += dangerousStyleValue(styleName, styleValue) + ';';
+ }
+ }
+ return serialized || null;
+ },
+
+ /**
+ * Sets the value for multiple styles on a node. If a value is specified as
+ * '' (empty string), the corresponding style property will be unset.
+ *
+ * @param {DOMElement} node
+ * @param {object} styles
+ */
+ setValueForStyles: function(node, styles) {
+ var style = node.style;
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ var styleValue = dangerousStyleValue(styleName, styles[styleName]);
+ if (styleValue) {
+ style[styleName] = styleValue;
+ } else {
+ var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+ if (expansion) {
+ // Shorthand property that IE8 won't like unsetting, so unset each
+ // component to placate it
+ for (var individualStyleName in expansion) {
+ style[individualStyleName] = '';
+ }
+ } else {
+ style[styleName] = '';
+ }
+ }
+ }
+ }
+
+};
+
+module.exports = CSSPropertyOperations;
+
+},{"./CSSProperty":3,"./dangerousStyleValue":107,"./escapeTextForBrowser":109,"./hyphenate":120,"./memoizeStringOnly":129}],5:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ChangeEventPlugin
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var ReactUpdates = require("./ReactUpdates");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var isEventSupported = require("./isEventSupported");
+var isTextInputElement = require("./isTextInputElement");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+ change: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onChange: null}),
+ captured: keyOf({onChangeCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topChange,
+ topLevelTypes.topClick,
+ topLevelTypes.topFocus,
+ topLevelTypes.topInput,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topSelectionChange
+ ]
+ }
+};
+
+/**
+ * For IE shims
+ */
+var activeElement = null;
+var activeElementID = null;
+var activeElementValue = null;
+var activeElementValueProp = null;
+
+/**
+ * SECTION: handle `change` event
+ */
+function shouldUseChangeEvent(elem) {
+ return (
+ elem.nodeName === 'SELECT' ||
+ (elem.nodeName === 'INPUT' && elem.type === 'file')
+ );
+}
+
+var doesChangeEventBubble = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // See `handleChange` comment below
+ doesChangeEventBubble = isEventSupported('change') && (
+ !('documentMode' in document) || document.documentMode > 8
+ );
+}
+
+function manualDispatchChangeEvent(nativeEvent) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ activeElementID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+
+ // If change and propertychange bubbled, we'd just bind to it like all the
+ // other events and have it go through ReactEventTopLevelCallback. Since it
+ // doesn't, we manually listen for the events and so we have to enqueue and
+ // process the abstract event manually.
+ //
+ // Batching is necessary here in order to ensure that all event handlers run
+ // before the next rerender (including event handlers attached to ancestor
+ // elements instead of directly on the input). Without this, controlled
+ // components don't work properly in conjunction with event bubbling because
+ // the component is rerendered and the value reverted before all the event
+ // handlers can run. See https://github.com/facebook/react/issues/708.
+ ReactUpdates.batchedUpdates(runEventInBatch, event);
+}
+
+function runEventInBatch(event) {
+ EventPluginHub.enqueueEvents(event);
+ EventPluginHub.processEventQueue();
+}
+
+function startWatchingForChangeEventIE8(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElement.attachEvent('onchange', manualDispatchChangeEvent);
+}
+
+function stopWatchingForChangeEventIE8() {
+ if (!activeElement) {
+ return;
+ }
+ activeElement.detachEvent('onchange', manualDispatchChangeEvent);
+ activeElement = null;
+ activeElementID = null;
+}
+
+function getTargetIDForChangeEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topChange) {
+ return topLevelTargetID;
+ }
+}
+function handleEventsForChangeEventIE8(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForChangeEventIE8();
+ startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForChangeEventIE8();
+ }
+}
+
+
+/**
+ * SECTION: handle `input` event
+ */
+var isInputEventSupported = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // IE9 claims to support the input event but fails to trigger it when
+ // deleting text, so we ignore its input events
+ isInputEventSupported = isEventSupported('input') && (
+ !('documentMode' in document) || document.documentMode > 9
+ );
+}
+
+/**
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
+ * set on the active element.
+ */
+var newValueProp = {
+ get: function() {
+ return activeElementValueProp.get.call(this);
+ },
+ set: function(val) {
+ // Cast to a string so we can do equality checks.
+ activeElementValue = '' + val;
+ activeElementValueProp.set.call(this, val);
+ }
+};
+
+/**
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
+ * and override the value property so that we can distinguish user events from
+ * value changes in JS.
+ */
+function startWatchingForValueChange(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElementValue = target.value;
+ activeElementValueProp = Object.getOwnPropertyDescriptor(
+ target.constructor.prototype,
+ 'value'
+ );
+
+ Object.defineProperty(activeElement, 'value', newValueProp);
+ activeElement.attachEvent('onpropertychange', handlePropertyChange);
+}
+
+/**
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
+ * if any exists.
+ */
+function stopWatchingForValueChange() {
+ if (!activeElement) {
+ return;
+ }
+
+ // delete restores the original property definition
+ delete activeElement.value;
+ activeElement.detachEvent('onpropertychange', handlePropertyChange);
+
+ activeElement = null;
+ activeElementID = null;
+ activeElementValue = null;
+ activeElementValueProp = null;
+}
+
+/**
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
+ * the value of the active element has changed.
+ */
+function handlePropertyChange(nativeEvent) {
+ if (nativeEvent.propertyName !== 'value') {
+ return;
+ }
+ var value = nativeEvent.srcElement.value;
+ if (value === activeElementValue) {
+ return;
+ }
+ activeElementValue = value;
+
+ manualDispatchChangeEvent(nativeEvent);
+}
+
+/**
+ * If a `change` event should be fired, returns the target's ID.
+ */
+function getTargetIDForInputEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topInput) {
+ // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
+ // what we want so fall through here and trigger an abstract event
+ return topLevelTargetID;
+ }
+}
+
+// For IE8 and IE9.
+function handleEventsForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // In IE8, we can capture almost all .value changes by adding a
+ // propertychange handler and looking for events with propertyName
+ // equal to 'value'
+ // In IE9, propertychange fires for most input events but is buggy and
+ // doesn't fire when text is deleted, but conveniently, selectionchange
+ // appears to fire in all of the remaining cases so we catch those and
+ // forward the event if the value has changed
+ // In either case, we don't want to call the event handler if the value
+ // is changed from JS so we redefine a setter for `.value` that updates
+ // our activeElementValue variable, allowing us to ignore those changes
+ //
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForValueChange();
+ startWatchingForValueChange(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForValueChange();
+ }
+}
+
+// For IE8 and IE9.
+function getTargetIDForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topSelectionChange ||
+ topLevelType === topLevelTypes.topKeyUp ||
+ topLevelType === topLevelTypes.topKeyDown) {
+ // On the selectionchange event, the target is just document which isn't
+ // helpful for us so just check activeElement instead.
+ //
+ // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
+ // propertychange on the first input event after setting `value` from a
+ // script and fires only keydown, keypress, keyup. Catching keyup usually
+ // gets it and catching keydown lets us fire an event for the first
+ // keystroke if user does a key repeat (it'll be a little delayed: right
+ // before the second keystroke). Other input methods (e.g., paste) seem to
+ // fire selectionchange normally.
+ if (activeElement && activeElement.value !== activeElementValue) {
+ activeElementValue = activeElement.value;
+ return activeElementID;
+ }
+ }
+}
+
+
+/**
+ * SECTION: handle `click` event
+ */
+function shouldUseClickEvent(elem) {
+ // Use the `click` event to detect changes to checkbox and radio inputs.
+ // This approach works across all browsers, whereas `change` does not fire
+ // until `blur` in IE8.
+ return (
+ elem.nodeName === 'INPUT' &&
+ (elem.type === 'checkbox' || elem.type === 'radio')
+ );
+}
+
+function getTargetIDForClickEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topClick) {
+ return topLevelTargetID;
+ }
+}
+
+/**
+ * This plugin creates an `onChange` event that normalizes change events
+ * across form elements. This event fires at a time when it's possible to
+ * change the element's value without seeing a flicker.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - select
+ */
+var ChangeEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var getTargetIDFunc, handleEventFunc;
+ if (shouldUseChangeEvent(topLevelTarget)) {
+ if (doesChangeEventBubble) {
+ getTargetIDFunc = getTargetIDForChangeEvent;
+ } else {
+ handleEventFunc = handleEventsForChangeEventIE8;
+ }
+ } else if (isTextInputElement(topLevelTarget)) {
+ if (isInputEventSupported) {
+ getTargetIDFunc = getTargetIDForInputEvent;
+ } else {
+ getTargetIDFunc = getTargetIDForInputEventIE;
+ handleEventFunc = handleEventsForInputEventIE;
+ }
+ } else if (shouldUseClickEvent(topLevelTarget)) {
+ getTargetIDFunc = getTargetIDForClickEvent;
+ }
+
+ if (getTargetIDFunc) {
+ var targetID = getTargetIDFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ if (targetID) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ targetID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+ }
+
+ if (handleEventFunc) {
+ handleEventFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ }
+ }
+
+};
+
+module.exports = ChangeEventPlugin;
+
+},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactUpdates":80,"./SyntheticEvent":88,"./isEventSupported":122,"./isTextInputElement":124,"./keyOf":128}],6:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ClientReactRootIndex
+ * @typechecks
+ */
+
+"use strict";
+
+var nextReactRootIndex = 0;
+
+var ClientReactRootIndex = {
+ createReactRootIndex: function() {
+ return nextReactRootIndex++;
+ }
+};
+
+module.exports = ClientReactRootIndex;
+
+},{}],7:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule CompositionEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var ReactInputSelection = require("./ReactInputSelection");
+var SyntheticCompositionEvent = require("./SyntheticCompositionEvent");
+
+var getTextContentAccessor = require("./getTextContentAccessor");
+var keyOf = require("./keyOf");
+
+var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
+var START_KEYCODE = 229;
+
+var useCompositionEvent = (
+ ExecutionEnvironment.canUseDOM &&
+ 'CompositionEvent' in window
+);
+
+// In IE9+, we have access to composition events, but the data supplied
+// by the native compositionend event may be incorrect. In Korean, for example,
+// the compositionend event contains only one character regardless of
+// how many characters have been composed since compositionstart.
+// We therefore use the fallback data while still using the native
+// events as triggers.
+var useFallbackData = (
+ !useCompositionEvent ||
+ 'documentMode' in document && document.documentMode > 8
+);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var currentComposition = null;
+
+// Events and their corresponding property names.
+var eventTypes = {
+ compositionEnd: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionEnd: null}),
+ captured: keyOf({onCompositionEndCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionEnd,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ },
+ compositionStart: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionStart: null}),
+ captured: keyOf({onCompositionStartCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionStart,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ },
+ compositionUpdate: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onCompositionUpdate: null}),
+ captured: keyOf({onCompositionUpdateCapture: null})
+ },
+ dependencies: [
+ topLevelTypes.topBlur,
+ topLevelTypes.topCompositionUpdate,
+ topLevelTypes.topKeyDown,
+ topLevelTypes.topKeyPress,
+ topLevelTypes.topKeyUp,
+ topLevelTypes.topMouseDown
+ ]
+ }
+};
+
+/**
+ * Translate native top level events into event types.
+ *
+ * @param {string} topLevelType
+ * @return {object}
+ */
+function getCompositionEventType(topLevelType) {
+ switch (topLevelType) {
+ case topLevelTypes.topCompositionStart:
+ return eventTypes.compositionStart;
+ case topLevelTypes.topCompositionEnd:
+ return eventTypes.compositionEnd;
+ case topLevelTypes.topCompositionUpdate:
+ return eventTypes.compositionUpdate;
+ }
+}
+
+/**
+ * Does our fallback best-guess model think this event signifies that
+ * composition has begun?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackStart(topLevelType, nativeEvent) {
+ return (
+ topLevelType === topLevelTypes.topKeyDown &&
+ nativeEvent.keyCode === START_KEYCODE
+ );
+}
+
+/**
+ * Does our fallback mode think that this event is the end of composition?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackEnd(topLevelType, nativeEvent) {
+ switch (topLevelType) {
+ case topLevelTypes.topKeyUp:
+ // Command keys insert or clear IME input.
+ return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
+ case topLevelTypes.topKeyDown:
+ // Expect IME keyCode on each keydown. If we get any other
+ // code we must have exited earlier.
+ return (nativeEvent.keyCode !== START_KEYCODE);
+ case topLevelTypes.topKeyPress:
+ case topLevelTypes.topMouseDown:
+ case topLevelTypes.topBlur:
+ // Events are not possible without cancelling IME.
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Helper class stores information about selection and document state
+ * so we can figure out what changed at a later date.
+ *
+ * @param {DOMEventTarget} root
+ */
+function FallbackCompositionState(root) {
+ this.root = root;
+ this.startSelection = ReactInputSelection.getSelection(root);
+ this.startValue = this.getText();
+}
+
+/**
+ * Get current text of input.
+ *
+ * @return {string}
+ */
+FallbackCompositionState.prototype.getText = function() {
+ return this.root.value || this.root[getTextContentAccessor()];
+};
+
+/**
+ * Text that has changed since the start of composition.
+ *
+ * @return {string}
+ */
+FallbackCompositionState.prototype.getData = function() {
+ var endValue = this.getText();
+ var prefixLength = this.startSelection.start;
+ var suffixLength = this.startValue.length - this.startSelection.end;
+
+ return endValue.substr(
+ prefixLength,
+ endValue.length - suffixLength - prefixLength
+ );
+};
+
+/**
+ * This plugin creates `onCompositionStart`, `onCompositionUpdate` and
+ * `onCompositionEnd` events on inputs, textareas and contentEditable
+ * nodes.
+ */
+var CompositionEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var eventType;
+ var data;
+
+ if (useCompositionEvent) {
+ eventType = getCompositionEventType(topLevelType);
+ } else if (!currentComposition) {
+ if (isFallbackStart(topLevelType, nativeEvent)) {
+ eventType = eventTypes.compositionStart;
+ }
+ } else if (isFallbackEnd(topLevelType, nativeEvent)) {
+ eventType = eventTypes.compositionEnd;
+ }
+
+ if (useFallbackData) {
+ // The current composition is stored statically and must not be
+ // overwritten while composition continues.
+ if (!currentComposition && eventType === eventTypes.compositionStart) {
+ currentComposition = new FallbackCompositionState(topLevelTarget);
+ } else if (eventType === eventTypes.compositionEnd) {
+ if (currentComposition) {
+ data = currentComposition.getData();
+ currentComposition = null;
+ }
+ }
+ }
+
+ if (eventType) {
+ var event = SyntheticCompositionEvent.getPooled(
+ eventType,
+ topLevelTargetID,
+ nativeEvent
+ );
+ if (data) {
+ // Inject data generated from fallback path into the synthetic event.
+ // This matches the property of native CompositionEventInterface.
+ event.data = data;
+ }
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+ }
+};
+
+module.exports = CompositionEventPlugin;
+
+},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactInputSelection":56,"./SyntheticCompositionEvent":86,"./getTextContentAccessor":118,"./keyOf":128}],8:[function(require,module,exports){
+/**
+ * Copyright 2013-2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DOMChildrenOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var Danger = require("./Danger");
+var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");
+
+var getTextContentAccessor = require("./getTextContentAccessor");
+
+/**
+ * The DOM property to use when setting text content.
+ *
+ * @type {string}
+ * @private
+ */
+var textContentAccessor = getTextContentAccessor();
+
+/**
+ * Inserts `childNode` as a child of `parentNode` at the `index`.
+ *
+ * @param {DOMElement} parentNode Parent node in which to insert.
+ * @param {DOMElement} childNode Child node to insert.
+ * @param {number} index Index at which to insert the child.
+ * @internal
+ */
+function insertChildAt(parentNode, childNode, index) {
+ var childNodes = parentNode.childNodes;
+ if (childNodes[index] === childNode) {
+ return;
+ }
+ // If `childNode` is already a child of `parentNode`, remove it so that
+ // computing `childNodes[index]` takes into account the removal.
+ if (childNode.parentNode === parentNode) {
+ parentNode.removeChild(childNode);
+ }
+ if (index >= childNodes.length) {
+ parentNode.appendChild(childNode);
+ } else {
+ parentNode.insertBefore(childNode, childNodes[index]);
+ }
+}
+
+/**
+ * Sets the text content of `node` to `text`.
+ *
+ * @param {DOMElement} node Node to change
+ * @param {string} text New text content
+ */
+var updateTextContent;
+if (textContentAccessor === 'textContent') {
+ updateTextContent = function(node, text) {
+ node.textContent = text;
+ };
+} else {
+ updateTextContent = function(node, text) {
+ // In order to preserve newlines correctly, we can't use .innerText to set
+ // the contents (see #1080), so we empty the element then append a text node
+ while (node.firstChild) {
+ node.removeChild(node.firstChild);
+ }
+ if (text) {
+ var doc = node.ownerDocument || document;
+ node.appendChild(doc.createTextNode(text));
+ }
+ };
+}
+
+/**
+ * Operations for updating with DOM children.
+ */
+var DOMChildrenOperations = {
+
+ dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
+
+ updateTextContent: updateTextContent,
+
+ /**
+ * Updates a component's children by processing a series of updates. The
+ * update configurations are each expected to have a `parentNode` property.
+ *
+ * @param {array