| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- #!/usr/bin/env node
- /* ***** BEGIN LICENSE BLOCK *****
- * Distributed under the BSD license:
- *
- * Copyright (c) 2010, Ajax.org B.V.
- * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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.
- *
- * ***** END LICENSE BLOCK ***** */
- var fs = require("fs");
- var path = require("path");
- var copy = require('architect-build/copy');
- var build = require('architect-build/build');
- var ACE_HOME = __dirname;
- var BUILD_DIR = ACE_HOME + "/build";
- var CACHE = {};
- function main(args) {
- if (args.indexOf("updateModes") !== -1) {
- return updateModes();
- }
- var type = "minimal";
- args = args.map(function(x) {
- if (x[0] == "-" && x[1] != "-")
- return "-" + x;
- return x;
- }).filter(Boolean);
- if (args[2] && (args[2][0] != "-" || args[2].indexOf("h") != -1))
- type = args[2];
- var i = args.indexOf("--target");
- if (i != -1 && args[i+1])
- BUILD_DIR = args[i+1];
- if (args.indexOf("--h") == -1) {
- if (type == "minimal") {
- buildAce({
- compress: args.indexOf("--m") != -1,
- noconflict: args.indexOf("--nc") != -1,
- shrinkwrap: args.indexOf("--s") != -1
- });
- } else if (type == "normal") {
- ace();
- } else if (type == "demo") {
- demo();
- } else if (type == "full") {
- ace();
- demo();
- } else if (type == "highlighter") {
- // TODO
- }
- }
- }
- function showHelp(type) {
- console.log("--- Ace Dryice Build Tool ---");
- console.log("");
- console.log("Options:");
- console.log(" minimal Places necessary Ace files out in build dir; uses configuration flags below [default]");
- console.log(" normal Runs four Ace builds--minimal, minimal-noconflict, minimal-min, and minimal-noconflict-min");
- console.log(" demo Runs demo build of Ace");
- console.log(" full all of above");
- console.log(" highlighter ");
- console.log("args:");
- console.log(" --target ./path path to build folder");
- console.log("flags:");
- console.log(" --h print this help");
- console.log(" --m minify");
- console.log(" --nc namespace require");
- console.log(" --s shrinkwrap (combines all output files into one)");
- console.log("");
- if (type)
- console.log(" output for " + type + " generated in " + BUILD_DIR);
- }
- function ace() {
- console.log('# ace License | Readme | Changelog ---------');
- copy.file(ACE_HOME + "/build_support/editor.html", BUILD_DIR + "/editor.html");
- copy.file(ACE_HOME + "/LICENSE", BUILD_DIR + "/LICENSE");
- copy.file(ACE_HOME + "/ChangeLog.txt", BUILD_DIR + "/ChangeLog.txt");
-
- console.log('# ace ---------');
- for (var i = 0; i < 4; i++)
- buildAce({compress: i & 2, noconflict: i & 1, check: true});
- }
- function demo() {
- console.log('# kitchen sink ---------');
- var version = "", ref = "";
- try {
- version = JSON.parse(fs.readFileSync(ACE_HOME + "/package.json")).version;
- ref = fs.readFileSync(ACE_HOME + "/.git-ref").toString();
- } catch(e) {}
- function changeComments(data) {
- return (data
- .replace("doc/site/images/ace-logo.png", "demo/kitchen-sink/ace-logo.png")
- .replace(/<!\-\-DEVEL[\d\D]*?DEVEL\-\->/g, "")
- .replace(/PACKAGE\-\->|<!\-\-PACKAGE/g, "")
- .replace(/\/\*DEVEL[\d\D]*?DEVEL\*\//g, "")
- .replace(/PACKAGE\*\/|\/\*PACKAGE/g, "")
- .replace("%version%", version)
- .replace("%commit%", ref)
- );
- }
-
- copy(ACE_HOME +"/demo/kitchen-sink/docs/", BUILD_DIR + "/demo/kitchen-sink/docs/");
-
- copy.file(ACE_HOME + "/demo/kitchen-sink/logo.png", BUILD_DIR + "/demo/kitchen-sink/logo.png");
- copy.file(ACE_HOME + "/demo/kitchen-sink/styles.css", BUILD_DIR + "/demo/kitchen-sink/styles.css");
- copy.file(ACE_HOME + "/kitchen-sink.html", BUILD_DIR + "/kitchen-sink.html", changeComments);
- buildSubmodule({}, {
- require: ["kitchen-sink/demo"],
- projectType: "demo"
- }, BUILD_DIR + "/demo/kitchen-sink/demo");
- copy(ACE_HOME + "/demo/", BUILD_DIR + "/demo/", {
- shallow: true,
- exclude: /\s|requirejs/,
- include: /\.(js|html)$/,
- replace: function(source) {
- if (!/^\s*</.test(source))
- return source;
- var removeRequireJS;
- source = source.replace(/<script src="kitchen-sink\/require.js"[\s\S]+?require\(\[([^\]]+).*/, function(e, m) {
- removeRequireJS = true;
- var scripts = m.split(/,\s*/);
- var result = [];
- function comment(str) {result.push("<!-- " + str + " -->")}
- function script(str) {result.push('<script src="../src/' + str + '.js"></script>')}
- scripts.forEach(function(s) {
- s = s.replace(/"/g, "");
- if (s == "ace/ace") {
- comment("load ace");
- script("ace");
- } else {
- var extName = s.match(/[^/]*$/)[0];
- comment("load ace " + extName + " extension");
- script("ext-" + extName);
- }
- });
- result.push("<script>");
- return result.join("\n");
- });
- if (removeRequireJS)
- source = source.replace(/\s*\}\);?\s*(<\/script>)/, "\n$1");
- source = source.replace(/"\.\.\/build\//g, function(e) {
- console.log(e); return '"../';
- });
- return source;
- }
- });
- }
- function jsFileList(path, filter) {
- path = ACE_HOME + "/" + path;
- if (!filter)
- filter = /_test/;
- return fs.readdirSync(path).map(function(x) {
- if (x.slice(-3) == ".js" && !filter.test(x) && !/\s|BASE|(\b|_)dummy(\b|_)/.test(x))
- return x.slice(0, -3);
- }).filter(Boolean);
- }
- function workers(path) {
- return jsFileList(path).map(function(x) {
- if (x.slice(-7) == "_worker")
- return x.slice(0, -7);
- }).filter(function(x) { return !!x; });
- }
- function modeList() {
- return jsFileList("lib/ace/mode", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/);
- }
- function buildAceModule(opts, callback) {
- // calling buildAceModuleInternal many times in parallel is slow, so we use queue
- if (!buildAceModule.queue) {
- buildAceModule.queue = [];
- buildAceModule.dequeue = function() {
- if (buildAceModule.running) return;
- var call = buildAceModule.queue.shift();
- buildAceModule.running = call;
- if (call)
- buildAceModuleInternal.apply(null, call);
- };
- }
-
- buildAceModule.queue.push([opts, function(err, result) {
- callback && callback(err, result);
- buildAceModule.running = null;
- buildAceModule.dequeue();
- }]);
- if (!buildAceModule.running) {
- buildAceModule.dequeue();
- } else {
- process.nextTick(buildAceModule.dequeue);
- }
- }
- function buildAceModuleInternal(opts, callback) {
- var cache = opts.cache == undefined ? CACHE : opts.cache;
- var key = opts.require + "|" + opts.projectType;
- if (cache && cache.configs && cache.configs[key])
- return write(null, cache.configs[key]);
-
- var pathConfig = {
- paths: {
- ace: ACE_HOME + "/lib/ace",
- "kitchen-sink": ACE_HOME + "/demo/kitchen-sink",
- build_support: ACE_HOME + "/build_support",
- },
- root: ACE_HOME
- };
-
- function write(err, result) {
- if (cache && key && !(cache.configs && cache.configs[key])) {
- cache.configs = cache.configs || Object.create(null);
- cache.configs[key] = result;
- result.sources = result.sources.map(function(pkg) {
- return {deps: pkg.deps};
- });
- }
-
- if (!opts.outputFile)
- return callback(err, result);
-
- var code = result.code;
- if (opts.compress) {
- if (!result.codeMin)
- result.codeMin = compress(result.code);
- code = result.codeMin;
- }
-
- var targetDir = getTargetDir(opts);
-
- var to = /^([\\/]|\w:)/.test(opts.outputFile)
- ? opts.outputFile
- : path.join(opts.outputFolder || targetDir, opts.outputFile);
-
- var filters = [];
- var ns = opts.ns || "ace";
- if (opts.filters)
- filters = filters.concat(opts.filters);
-
- if (opts.noconflict)
- filters.push(namespace(ns));
- var projectType = opts.projectType;
- if (projectType == "main" || projectType == "ext") {
- filters.push(exportAce(ns, opts.require[0],
- opts.noconflict ? ns : "", projectType == "ext"));
- }
-
- filters.push(normalizeLineEndings);
-
- filters.forEach(function(f) { code = f(code); });
-
- build.writeToFile({code: code}, {
- outputFolder: path.dirname(to),
- outputFile: path.basename(to),
- }, function() {});
-
- callback && callback(err, result);
- }
-
- build(opts.require, {
- cache: cache,
- quiet: opts.quiet,
- pathConfig: pathConfig,
- additional: opts.additional,
- enableBrowser: true,
- keepDepArrays: "all",
- noArchitect: true,
- compress: false,
- ignore: opts.ignore || [],
- withRequire: false,
- basepath: ACE_HOME,
- transforms: [normalizeLineEndings],
- afterRead: [optimizeTextModules]
- }, write);
- }
- function buildCore(options, extra, callback) {
- options = extend(extra, options);
- options.additional = [{
- id: "build_support/mini_require",
- order: -1000,
- literal: true
- }];
- options.require =["ace/ace"];
- options.projectType = "main";
- options.ns = "ace";
- buildAceModule(options, callback);
- }
- function buildSubmodule(options, extra, file, callback) {
- options = extend(extra, options);
- getLoadedFileList(options, function(coreFiles) {
- options.outputFile = file + ".js";
- options.ignore = options.ignore || coreFiles;
- options.quiet = true;
- buildAceModule(options, callback);
- });
- }
- function buildAce(options) {
- var snippetFiles = jsFileList("lib/ace/snippets");
- var modeNames = modeList();
- buildCore(options, {outputFile: "ace.js"}, addCb()),
- // modes
- modeNames.forEach(function(name) {
- buildSubmodule(options, {
- projectType: "mode",
- require: ["ace/mode/" + name]
- }, "mode-" + name, addCb());
- });
- // snippets
- modeNames.forEach(function(name) {
- if (snippetFiles.indexOf(name + ".js") == -1)
- addSnippetFile(name);
-
- buildSubmodule(options, {
- require: ["ace/snippets/" + name],
- }, "snippets/" + name, addCb());
- });
- // themes
- jsFileList("lib/ace/theme").forEach(function(name) {
- buildSubmodule(options, {
- projectType: "theme",
- require: ["ace/theme/" + name]
- }, "theme-" + name, addCb());
- });
- // keybindings
- ["vim", "emacs"].forEach(function(name) {
- buildSubmodule(options, {
- projectType: "keybinding",
- require: ["ace/keyboard/" + name ]
- }, "keybinding-" + name, addCb());
- });
- // extensions
- jsFileList("lib/ace/ext").forEach(function(name) {
- buildSubmodule(options, {
- projectType: "ext",
- require: ["ace/ext/" + name]
- }, "ext-" + name, addCb());
- });
- // workers
- workers("lib/ace/mode").forEach(function(name) {
- buildSubmodule(options, {
- projectType: "worker",
- require: ["ace/mode/" + name + "_worker"],
- ignore: [],
- additional: [{
- id: "ace/worker/worker",
- transforms: [],
- order: -1000
- }],
- }, "worker-" + name, addCb());
- });
- //
- function addCb() {
- addCb.count = (addCb.count || 0) + 1;
- return done
- }
- function done() {
- if (--addCb.count > 0)
- return;
- if (options.check)
- sanityCheck(options)
- console.log("Finished building " + getTargetDir(options))
- }
- }
- function getLoadedFileList(options, callback, result) {
- if (!result) {
- return buildCore({}, {}, function(e, result) {
- getLoadedFileList(options, callback, result);
- });
- }
- var deps = Object.create(null);
- result.sources.forEach(function(pkg) {
- pkg.deps && pkg.deps.forEach(function(p) {
- if (!deps[p]) deps[p] = 1;
- });
- });
- delete deps["ace/theme/textmate"];
- deps["ace/ace"] = 1;
- callback(Object.keys(deps));
- }
- function normalizeLineEndings(module) {
- if (typeof module == "string")
- module = {source: module};
- return module.source = module.source.replace(/\r\n/g, "\n");
- }
- function optimizeTextModules(sources) {
- var textModules = {};
- return sources.filter(function(pkg) {
- if (!pkg.id) {
- return true;
- }
- else if (pkg.id.indexOf("text!") > -1) {
- detectTextModules(pkg);
- return false;
- }
- else {
- pkg.source = rewriteTextImports(pkg.source, pkg.deps);
- return true;
- }
- }).map(function(pkg) {
- if (pkg && pkg.deps) {
- pkg.deps = pkg.deps && pkg.deps.filter(function(p) {
- return p.indexOf("text!") == -1;
- });
- }
- return pkg;
- });
-
- function rewriteTextImports(text, deps) {
- return text.replace(/ require\(['"](?:ace|[.\/]+)\/requirejs\/text!(.*?)['"]\)/g, function(_, call) {
- if (call) {
- var dep;
- deps.some(function(d) {
- if (d.split("/").pop() == call.split("/").pop()) {
- dep = d;
- return true;
- }
- });
-
- call = textModules[dep];
- if (call)
- return " " + call;
- }
- });
- }
- function detectTextModules(pkg) {
- var input = pkg.source.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
- if (/\.css$/.test(pkg.id)) {
- // remove unnecessary whitespace from css
- input = input.replace(/\n\s+/g, "\n");
- input = '"' + input.replace(/\n/g, '\\\n') + '"';
- } else {
- // but don't break other files!
- input = '"' + input.replace(/\n/g, '\\n\\\n') + '"';
- }
- textModules[pkg.id] = input;
- }
- }
- function namespace(ns) {
- return function(text) {
- text = text
- .toString()
- .replace(/ACE_NAMESPACE\s*=\s*""/, 'ACE_NAMESPACE = "' + ns +'"')
- .replace(/\bdefine\(/g, function(def, index, source) {
- if (/(^|[;}),])\s*$/.test(source.slice(0, index)))
- return ns + "." + def;
- return def;
- });
- return text;
- };
- }
- function exportAce(ns, modules, requireBase, extModules) {
- requireBase = requireBase || "window";
- return function(text) {
- /*globals REQUIRE_NS, MODULES, NS*/
- var template = function() {
- (function() {
- REQUIRE_NS.require(MODULES, function(a) {
- a && a.config.init(true);
- if (!window.NS)
- window.NS = a;
- for (var key in a) if (a.hasOwnProperty(key))
- window.NS[key] = a[key];
- });
- })();
- };
-
- if (extModules) {
- template = function() {
- (function() {
- REQUIRE_NS.require(MODULES, function() {});
- })();
- };
- }
-
- text = text.replace(/function init\(packaged\) {/, "init(true);$&\n");
-
- if (typeof modules == "string")
- modules = [modules];
-
- return (text.replace(/;\s*$/, "") + ";" + template
- .toString()
- .replace(/MODULES/g, JSON.stringify(modules))
- .replace(/REQUIRE_NS/g, requireBase)
- .replace(/NS/g, ns)
- .slice(13, -1)
- );
- };
- }
- function updateModes() {
- modeList().forEach(function(m) {
- var filepath = __dirname + "/lib/ace/mode/" + m + ".js";
- var source = fs.readFileSync(filepath, "utf8");
- if (!/this.\$id\s*=\s*"/.test(source))
- source = source.replace(/\n([ \t]*)(\}\).call\(\w*Mode.prototype\))/, '\n$1 this.$id = "";\n$1$2');
-
- source = source.replace(/(this.\$id\s*=\s*)"[^"]*"/, '$1"ace/mode/' + m + '"');
- fs.writeFileSync(filepath, source, "utf8");
- });
- }
- function generateThemesModule(themes) {
- var themelist = [
- 'define(function(require, exports, module) {',
- '\n\nmodule.exports.themes = ' + JSON.stringify(themes, null, ' '),
- ';\n\n});'
- ].join('');
- fs.writeFileSync(__dirname + '/lib/ace/ext/themelist_utils/themes.js', themelist, 'utf8');
- }
- function addSnippetFile(modeName) {
- var snippetFilePath = ACE_HOME + "/lib/ace/snippets/" + modeName;
- if (!fs.existsSync(snippetFilePath + ".js")) {
- copy.file(ACE_HOME + "/tool/templates/snippets.js", snippetFilePath + ".js", function(t) {
- return t.replace(/%modeName%/g, modeName);
- });
- }
- if (!fs.existsSync(snippetFilePath + ".snippets")) {
- fs.writeFileSync(snippetFilePath + ".snippets", "");
- }
- }
- function compress(text) {
- var ujs = require("dryice").copy.filter.uglifyjs;
- ujs.options.mangle_toplevel = {except: ["ACE_NAMESPACE", "requirejs"]};
- ujs.options.beautify = {ascii_only: true, inline_script: true}
- return ujs(text);
- }
- function extend(base, extra) {
- Object.keys(extra).forEach(function(k) {
- base[k] = extra[k];
- });
- return base;
- }
- function getTargetDir(opts) {
- var targetDir = BUILD_DIR + "/src";
- if (opts.compress)
- targetDir += "-min";
- if (opts.noconflict)
- targetDir += "-noconflict";
- return targetDir;
- }
- function sanityCheck(opts) {
- var targetDir = getTargetDir(opts);
- require("child_process").execFile(process.execPath, ["-e", "(" + function() {
- window = global;
- require("./ace");
- if (typeof ace.edit != "function")
- process.exit(1);
- require("fs").readdirSync(".").forEach(function(p) {
- if (!/ace\.js$/.test(p) && /\.js$/.test(p))
- require("./" + p);
- });
- process.exit(0);
- } + ")()"], {
- cwd: targetDir
- }, function(err, stdout) {
- if (err)
- throw err;
- });
- }
- if (!module.parent)
- main(process.argv);
- else
- exports.buildAce = buildAce;
|