UNPKG

jsx

Version:

a faster, safer, easier JavaScript

333 lines (278 loc) 9.67 kB
/*** * The entry point module of JSX compiler on browsers, * deployed http://jsx.github.io/try-on-web */ /* * Copyright (c) 2012 DeNA Co., Ltd. * * 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. */ import "console.jsx"; import "js.jsx"; import "js/web.jsx"; import "./browser-platform.jsx"; import "../compiler.jsx"; import "../optimizer.jsx"; import "../jsemitter.jsx"; import "../completion.jsx"; native __fake__ class Cursor { var line : number; var ch : number; } native __fake__ class CodeMirror { function getValue() : string; function setValue(value : string) : void; function getCursor() : Cursor; function setCursor(line : number, ch : number) : void; function replaceSelection(s : string) : void; function setSelection(c : Cursor) : void; function setOption(option : string, value : variant) : void; static function fromTextArea(textArea : Element, options : variant) : CodeMirror; // addons: show-hint.js static function showHint(cm : CodeMirror, callback : (CodeMirror) -> variant) : void; } class _Main { static function main(args : string[]) : void { function getOptimizationLevel() : number { var items = dom.document.getElementsByName("optimization-level"); for(var i = 0; i < items.length; ++i) { var item = items[i] as HTMLInputElement; if(item.checked) { return item.value as number; } } return 0; } function jsxComplete(cm : CodeMirror) : void { CodeMirror.showHint(cm, function (editor) { var cur = editor.getCursor(); var completionRequest = new CompletionRequest(cur.line+1, cur.ch); var path = "<source>"; var platform = new BrowserPlatform(); platform.setFileContent(path, editor.getValue()); var c = new Compiler(platform); var emitter = new JavaScriptEmitter(platform); c.setEmitter(emitter); c.setMode(Compiler.MODE_COMPLETE); c.addSourceFile(null, path, completionRequest); c.compile(); var ret = {} : variant; var uniq = new Map.<boolean>; ret['list'] = completionRequest.getCandidates().map.<string>(function (item) { return (item["partialWord"] ?: item["word"]) as string; }).filter(function (item) { if (! uniq.hasOwnProperty(item)) { uniq[item] = true; return true; } else { return false; } }); ret['from'] = { line: cur.line, ch: cur.ch }; ret['to'] = { line: cur.line, ch: cur.ch }; return ret; }); } var list = dom.id('source-list'); var input = dom.id('input') as HTMLTextAreaElement; var editor = CodeMirror.fromTextArea(input, { mode: "application/jsx", lineNumbers: true, lineWrapping: true, autofocus: true, extraKeys: { "Ctrl-Space": jsxComplete, "Ctrl-P": jsxComplete, "." : function (editor : CodeMirror) : void { editor.replaceSelection("."); var cursor = editor.getCursor(); editor.setSelection(cursor); jsxComplete(editor); }, "'\u00A5'" /* yen mark */ : function (editor: CodeMirror) : void { editor.replaceSelection("\u005c"); // backslash var cursor = editor.getCursor(); editor.setSelection(cursor); } } } : Map.<variant>); var output = CodeMirror.fromTextArea(dom.id("output"), { mode: "javascript", lineNumbers: true, lineWrapping: true, readOnly: true } : Map.<variant>); var console_log = js.global["console"]["log"]; function compile(options : variant) : void { console.info('compile with ' + JSON.stringify(options)); output.setValue(""); var path = input.dataset["path"]; var platform = new BrowserPlatform(); platform.setFileContent(path, editor.getValue()); var c = new Compiler(platform); var emitter = new JavaScriptEmitter(platform); c.setEmitter(emitter); var o = new Optimizer(); if(getOptimizationLevel() > 0) { var optimizeCommands = Optimizer.getReleaseOptimizationCommands().filter((command) -> { return command != "no-log"; }); o.setup(optimizeCommands); o.setEnableRunTimeTypeCheck(false); emitter.setEnableRunTimeTypeCheck(false); } c.setOptimizer(o); switch(options['mode'] as string) { case "run": case "compile": c.setMode(Compiler.MODE_COMPILE); break; case "parse": c.setMode(Compiler.MODE_PARSE); break; default: dom.window.alert("unknown mode: " + options['mode'] as string); return; } if (options['mode'] == "run") { js.global["console"]["log"] = function (arg : string) : void { output.setValue(output.getValue() + arg + "\n"); }; } else { js.global["console"]["log"] = console_log; } c.addSourceFile(null, path); var success = c.compile(); if (success) { if (options['mode'] == 'parse') { output.setOption("mode", "javascript"); output.setValue(JSON.stringify(c.getAST(), null, 2)); return; } var out = emitter.getOutput().replace(/\t/g, " "); out += "JSX.require('"+path+"')._Main.main$AS([]);\n"; var level = getOptimizationLevel(); if(level > 1 && options['mode'] != 'parse') { out = platform.applyClosureCompiler(out, level <= 2 ? "SIMPLE_OPTIMIZATIONS" : "ADVANCED_OPTIMIZATIONS", false); } if(options['mode'] == 'run') { output.setOption("mode", ""); js.eval(out); } else { output.setOption("mode", "javascript"); output.setValue(out); } } else if(platform.getErrors().length != 0){ output.setOption("mode", ""); output.setValue("ERROR!\n" + platform.getErrors().join("")); } } function saveInput(input : HTMLTextAreaElement) : void { var session = { inputPath: input.dataset["path"], source: editor.getValue(), cursor: editor.getCursor(), optimizationLevel: getOptimizationLevel() } : Map.<variant>; dom.window.sessionStorage.setItem("jsx.session", JSON.stringify(session)); } function retrieveInput(input : HTMLTextAreaElement) : void { var serializedSession = dom.window.sessionStorage.getItem("jsx.session"); if(serializedSession) { console.info("retrieve from session"); var session = JSON.parse(serializedSession); input.dataset["path"] = session['inputPath'] as string; editor.setValue(session['source'] as string); editor.setCursor(session['cursor']['line'] as number, session['cursor']['ch'] as number); var items = dom.document.getElementsByName("optimization-level"); for(var i = 0; i < items.length; ++i) { var item = items[i] as HTMLInputElement; if(item.value == (session['optimizationLevel'] as string)) { item.checked = true; } else { item.checked = false; } } compile({ mode: 'run' }); } } function forEach(collection : HTMLCollection, block : (Object) -> void) : void { for(var i = 0; i < collection.length; ++i) { block(collection[i]); } } // set up example souce files forEach(list.getElementsByTagName("li"), function(elem) { var li = elem as HTMLLIElement; if(li.className != "source-file") return; var a = li.children[0] as HTMLAnchorElement; a.addEventListener('click', function(event) { console.info('changing'); event.preventDefault(); event.stopPropagation(); input.dataset["path"] = a.dataset["path"]; var url = a.href; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(e) { if (xhr.readyState != 4) return; editor.setValue(xhr.responseText.replace(/\t/g, " ")); forEach(list.getElementsByTagName("li"), function(el) { var li = el as HTMLLIElement; if(!li.className.match(/\bsource-file\b/)) return; li.className = "source-file"; }); li.className = "source-file active"; compile({ mode: "run" }); }; xhr.open("GET", url); xhr.send(null : Blob); }); }); dom.window.addEventListener('keyup', function(e) { var event = e as KeyboardEvent; if(event.ctrlKey) { event.preventDefault(); event.stopPropagation(); var RUN_KEY = "R".charCodeAt(0); var COMPILE_KEY = "C".charCodeAt(0); if(event.keyCode == RUN_KEY) { compile({ mode: 'run' }); } else if(event.keyCode == COMPILE_KEY) { compile({ mode: 'compile' }); } } }); dom.window.addEventListener('unload', function(e) { saveInput(input); }); dom.id('run').addEventListener('click', function(e) { compile({mode: 'run'}); }); dom.id('compile').addEventListener('click', function(e) { compile({mode: 'compile'}); }); dom.id('ast').addEventListener('click', function(e) { compile({mode: 'parse'}); }); retrieveInput(input); } }