diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base-compiler.js | 37 | ||||
-rw-r--r-- | lib/compilation-env.js | 18 | ||||
-rw-r--r-- | lib/compile-handler.js | 109 | ||||
-rw-r--r-- | lib/compilers/WSL-CL.js | 6 | ||||
-rw-r--r-- | lib/compilers/Wine-CL.js | 8 | ||||
-rw-r--r-- | lib/compilers/default.js | 4 | ||||
-rw-r--r-- | lib/compilers/golang.js | 6 | ||||
-rw-r--r-- | lib/compilers/haskell.js | 4 | ||||
-rw-r--r-- | lib/compilers/ispc.js | 4 | ||||
-rw-r--r-- | lib/compilers/ldc.js | 4 | ||||
-rw-r--r-- | lib/compilers/pascal.js | 5 | ||||
-rw-r--r-- | lib/compilers/rust.js | 4 | ||||
-rw-r--r-- | lib/compilers/swift.js | 4 | ||||
-rw-r--r-- | lib/languages.js | 116 | ||||
-rw-r--r-- | lib/sources/builtin.js | 42 |
15 files changed, 259 insertions, 112 deletions
diff --git a/lib/base-compiler.js b/lib/base-compiler.js index 21c60f28f..3788aea22 100644 --- a/lib/base-compiler.js +++ b/lib/base-compiler.js @@ -34,12 +34,20 @@ const child_process = require('child_process'), logger = require('./logger').logger, compilerOptInfo = require("compiler-opt-info"), argumentParsers = require("./compilers/argument-parsers"), - cfg = require('./cfg'); + cfg = require('./cfg'), + languages = require('./languages').list; -function Compile(compiler, env) { +function Compile(compiler, env, langId) { this.compiler = compiler; + this.lang = langId; + this.langInfo = languages[langId]; + if (!this.langInfo) { + throw new Error("Missing language info for " + langId); + } + this.compileFilename = 'example' + this.langInfo.extensions[0]; this.env = env; - this.asm = new asm.AsmParser(env.compilerProps); + this.compilerProps = _.partial(this.env.compilerPropsL, this.lang); + this.asm = new asm.AsmParser(this.compilerProps); this.compiler.supportsIntel = !!this.compiler.intelAsm; } @@ -75,10 +83,10 @@ Compile.prototype.exec = function (compiler, args, options) { Compile.prototype.getDefaultExecOptions = function () { return { - timeoutMs: this.env.gccProps("compileTimeoutMs", 100), - maxErrorOutput: this.env.gccProps("max-error-output", 5000), + timeoutMs: this.env.ceProps("compileTimeoutMs", 100), + maxErrorOutput: this.env.ceProps("max-error-output", 5000), env: this.env.getEnv(this.compiler.needsMulti), - wrapper: this.env.compilerProps("compiler-wrapper") + wrapper: this.compilerProps("compiler-wrapper") }; }; @@ -226,13 +234,13 @@ Compile.prototype.compile = function (source, options, backendOptions, filters) return Promise.resolve(cached); } - if (filters.binary && !source.match(this.env.compilerProps("stubRe"))) { - source += "\n" + this.env.compilerProps("stubText") + "\n"; + if (filters.binary && !source.match(this.compilerProps("stubRe"))) { + source += "\n" + this.compilerProps("stubText") + "\n"; } return this.env.enqueue(() => { const tempFileAndDirPromise = this.newTempDir() .then(dirPath => { - const inputFilename = path.join(dirPath, this.env.compilerProps("compileFilename")); + const inputFilename = path.join(dirPath, this.compileFilename); return this.writeFile(inputFilename, source).then(() => ({ inputFilename: inputFilename, dirPath: dirPath @@ -357,8 +365,7 @@ Compile.prototype.postProcessAsm = function (result) { }; Compile.prototype.processOptOutput = function (hasOptOutput, optPath) { - const output = []; - const inputFile = this.env.compilerProps("compileFilename", ""); + let output = []; return new Promise( resolve => { fs.createReadStream(optPath, {encoding: "utf-8"}) @@ -366,7 +373,7 @@ Compile.prototype.processOptOutput = function (hasOptOutput, optPath) { .on("data", opt => { if (opt.DebugLoc && opt.DebugLoc.File && - opt.DebugLoc.File.indexOf(inputFile) > -1) { + opt.DebugLoc.File.indexOf(this.compileFilename) > -1) { output.push(opt); } @@ -519,7 +526,7 @@ Compile.prototype.processGccDumpOutput = function (opts, result) { Compile.prototype.postProcess = function (result, outputFilename, filters) { const postProcess = _.compact(this.compiler.postProcess); - const maxSize = this.env.gccProps("max-asm-size", 8 * 1024 * 1024); + const maxSize = this.env.ceProps("max-asm-size", 8 * 1024 * 1024); let optPromise, asmPromise, execPromise; if (result.hasOptOutput) { optPromise = this.processOptOutput(result.hasOptOutput, result.optPath); @@ -555,7 +562,7 @@ Compile.prototype.postProcess = function (result, outputFilename, filters) { ); } if (filters.execute) { - const maxExecOutputSize = this.env.gccProps("max-executable-output-size", 32 * 1024); + const maxExecOutputSize = this.env.ceProps("max-executable-output-size", 32 * 1024); execPromise = this.execBinary(outputFilename, result, maxExecOutputSize); } else { execPromise = Promise.resolve(""); @@ -635,7 +642,7 @@ Compile.prototype.initialise = function () { 'with re', versionRe); return null; } - logger.info(compiler + " is version '" + version + "'"); + logger.debug(compiler + " is version '" + version + "'"); this.compiler.version = version; return argumentParser(this); }, diff --git a/lib/compilation-env.js b/lib/compilation-env.js index 81f21e54a..1d2d7b6cb 100644 --- a/lib/compilation-env.js +++ b/lib/compilation-env.js @@ -32,20 +32,18 @@ const LRU = require('lru-cache'), Queue.configure(Promise); -function CompilationEnvironment(gccProps, compilerProps) { - this.gccProps = gccProps; - this.compilerProps = compilerProps; - this.okOptions = new RegExp(gccProps('optionsWhitelistRe', '.*')); - this.badOptions = new RegExp(gccProps('optionsBlacklistRe', '(?!)')); +function CompilationEnvironment(ceProps, compilerPropsL) { + this.ceProps = ceProps; + this.compilerPropsL = compilerPropsL; + this.okOptions = new RegExp(ceProps('optionsWhitelistRe', '.*')); + this.badOptions = new RegExp(ceProps('optionsBlacklistRe', '(?!)')); this.cache = LRU({ - max: gccProps('cacheMb') * 1024 * 1024, - length: function (n) { - return JSON.stringify(n).length; - } + max: ceProps('cacheMb') * 1024 * 1024, + length: n => JSON.stringify(n).length }); this.cacheHits = 0; this.cacheMisses = 0; - this.compileQueue = new Queue(gccProps("maxConcurrentCompiles", 1), Infinity); + this.compileQueue = new Queue(ceProps("maxConcurrentCompiles", 1), Infinity); this.multiarch = null; try { var multi = child_process.execSync("gcc -print-multiarch").toString().trim(); diff --git a/lib/compile-handler.js b/lib/compile-handler.js index 1cbde43f4..159c5eeb5 100644 --- a/lib/compile-handler.js +++ b/lib/compile-handler.js @@ -22,8 +22,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -var child_process = require('child_process'), - temp = require('temp'), +const temp = require('temp'), fs = require('fs'), path = require('path'), httpProxy = require('http-proxy'), @@ -37,12 +36,12 @@ var child_process = require('child_process'), temp.track(); -var oneTimeInit = false; +let oneTimeInit = false; -function initialise(gccProps, compilerEnv) { +function initialise(ceProps, compilerEnv) { if (oneTimeInit) return; oneTimeInit = true; - var tempDirCleanupSecs = gccProps("tempDirCleanupSecs", 600); + const tempDirCleanupSecs = ceProps("tempDirCleanupSecs", 600); logger.info("Cleaning temp dirs every " + tempDirCleanupSecs + " secs"); setInterval(function () { if (compilerEnv.isBusy()) { @@ -56,71 +55,61 @@ function initialise(gccProps, compilerEnv) { }, tempDirCleanupSecs * 1000); } -function CompileHandler(gccProps, compilerProps) { +function CompileHandler(ceProps, compilerPropsL) { + const self = this; this.compilersById = {}; - this.compilerEnv = new CompilationEnvironment(gccProps, compilerProps); - initialise(gccProps, this.compilerEnv); + this.compilerEnv = new CompilationEnvironment(ceProps, compilerPropsL); + initialise(ceProps, this.compilerEnv); this.factories = {}; this.stat = Promise.denodeify(fs.stat); + this.proxy = httpProxy.createProxyServer({}); + this.textBanner = ceProps('textBanner'); + this.create = function (compiler) { - var type = compiler.compilerType || "default"; - if (this.factories[type] === undefined) { - var compilerPath = './compilers/' + type; - logger.info("Loading compiler from", compilerPath); - this.factories[type] = require(compilerPath); + const type = compiler.compilerType || "default"; + if (self.factories[type] === undefined) { + const compilerPath = './compilers/' + type; + logger.debug("Loading compiler from", compilerPath); + self.factories[type] = require(compilerPath); } if (path.isAbsolute(compiler.exe)) { // Try stat'ing the compiler to cache its mtime and only re-run it if it // has changed since the last time. - return this.stat(compiler.exe) - .then(_.bind(function (res) { - var cached = this.compilersById[compiler.id]; + return self.stat(compiler.exe) + .then(_.bind(res => { + const cached = self.findCompiler(compiler.lang, compiler.id); if (cached && cached.mtime.getTime() === res.mtime.getTime()) { logger.debug(compiler.id + " is unchanged"); return cached; } - return this.factories[type](compiler, this.compilerEnv).then(function (compiler) { + return self.factories[type](compiler, self.compilerEnv, compiler.lang).then(compiler => { compiler.mtime = res.mtime; return compiler; }); - }, this)) - .catch(function (err) { + }, self)) + .catch(err => { logger.warn("Unable to stat compiler binary", err); return null; }); } else { - return this.factories[type](compiler, this.compilerEnv); + return self.factories[type](compiler, self.compilerEnv, compiler.lang); } }; - - this.setCompilers = function (compilers) { - return Promise.all(_.map(compilers, this.create, this)) - .then(_.compact) - .then(compilers => { - _.each(compilers, compiler => this.compilersById[compiler.compiler.id] = compiler); - return _.map(compilers, compiler => compiler.getInfo()); - }) - .catch(err => logger.error(err)); - }; - var proxy = httpProxy.createProxyServer({}); - var textBanner = compilerProps('textBanner'); - - this.handler = _.bind(function compile(req, res, next) { - var source, options, backendOptions, filters, compiler; + this.handler = function compile(req, res, next) { + let source, options, backendOptions, filters, + compiler = self.findCompiler(req.lang || req.body.lang, req.compiler || req.body.compiler); + if (!compiler) return next(); if (req.is('json')) { // JSON-style request - compiler = this.compilersById[req.compiler || req.body.compiler]; - if (!compiler) return next(); - var requestOptions = req.body.options; + const requestOptions = req.body.options; source = req.body.source; options = requestOptions.userArguments; backendOptions = requestOptions.compilerOptions; filters = requestOptions.filters || compiler.getDefaultFilters(); } else { // API-style - compiler = this.compilersById[req.compiler]; - if (!compiler) return next(); + // Find the compiler the user is interested in... source = req.body; options = req.query.options; // By default we get the default filters. @@ -140,10 +129,10 @@ function CompileHandler(gccProps, compilerProps) { delete filters[filter]; }); } - var remote = compiler.getRemote(); + const remote = compiler.getRemote(); if (remote) { req.url = req.originalUrl; // Undo any routing that was done to get here (i.e. /api/* path has been removed) - proxy.web(req, res, {target: remote}, function (e) { + self.proxy.web(req, res, {target: remote}, function (e) { logger.error("Proxy error: ", e); next(e); }); @@ -170,7 +159,7 @@ function CompileHandler(gccProps, compilerProps) { } else { res.set('Content-Type', 'text/plain'); try { - if (!_.isEmpty(textBanner)) res.write('# ' + textBanner + "\n"); + if (!_.isEmpty(self.textBanner)) res.write('# ' + self.textBanner + "\n"); res.write(textify(result.asm)); if (result.code !== 0) res.write("\n# Compiler exited with result code " + result.code); if (!_.isEmpty(result.stdout)) res.write("\nStandard out:\n" + textify(result.stdout)); @@ -198,7 +187,39 @@ function CompileHandler(gccProps, compilerProps) { res.end(JSON.stringify({code: -1, stderr: [{text: error}]})); } ); - }, this); + }; + this.setCompilers = function (newCompilers) { + // Delete every compiler first... + self.compilersById = {}; + return Promise.all(_.map(newCompilers, self.create)) + .then(_.compact) + .then(compilers => { + _.each(compilers, compiler => { + const langId = compiler.compiler.lang; + if (!self.compilersById[langId]) self.compilersById[langId] = {}; + self.compilersById[langId][compiler.compiler.id] = compiler; + }, self); + return _.map(compilers,compiler => compiler.getInfo()); + }) + .catch(logger.error); + }; + this.findCompiler = function (langId, compilerId) { + if (langId && self.compilersById[langId]) { + return self.compilersById[langId][compilerId]; + } + // If the lang is bad, try to find it in every language + let response; + _.each(self.compilersById, compilerInLang => { + if (response === undefined) { + _.each(compilerInLang, compiler => { + if (response === undefined && compiler.compiler.id === compilerId) { + response = compiler; + } + }); + } + }); + return response; + }; } module.exports = { diff --git a/lib/compilers/WSL-CL.js b/lib/compilers/WSL-CL.js index 4582e546b..be3bc21c4 100644 --- a/lib/compilers/WSL-CL.js +++ b/lib/compilers/WSL-CL.js @@ -32,9 +32,9 @@ const Compile = require('../base-compiler'), asm = require('../asm-cl'), temp = require('temp'); -function compileCl(info, env) { - const compile = new Compile(info, env); - compile.asm = new asm.AsmParser(env.compilerProps); +function compileCl(info, env, langId) { + var compile = new Compile(info, env, langId); + compile.asm = new asm.AsmParser(compile.compilerProps); info.supportsFiltersInBinary = true; if (process.platform === "linux") { const origExec = compile.exec; diff --git a/lib/compilers/Wine-CL.js b/lib/compilers/Wine-CL.js index 0e92fe4de..d206bb0f2 100644 --- a/lib/compilers/Wine-CL.js +++ b/lib/compilers/Wine-CL.js @@ -25,12 +25,12 @@ var Compile = require('../base-compiler'); var asm = require('../asm-cl'); -function compileCl(info, env) { - var compile = new Compile(info, env); - compile.asm = new asm.AsmParser(env.compilerProps); +function compileCl(info, env, langId) { + var compile = new Compile(info, env, langId); + compile.asm = new asm.AsmParser(compile.compilerProps); info.supportsFiltersInBinary = true; if (process.platform == "linux") { - var wine = env.gccProps("wine"); + var wine = env.ceProps("wine"); var origExec = compile.exec; compile.exec = function (command, args, options) { if (command.toLowerCase().endsWith(".exe")) { diff --git a/lib/compilers/default.js b/lib/compilers/default.js index 759d2bbe8..64a542760 100644 --- a/lib/compilers/default.js +++ b/lib/compilers/default.js @@ -24,7 +24,7 @@ const Compile = require('../base-compiler'); -module.exports = function (info, env) { - var comp = new Compile(info, env); +module.exports = function (info, env, langId) { + var comp = new Compile(info, env, langId); return comp.initialise(); };
\ No newline at end of file diff --git a/lib/compilers/golang.js b/lib/compilers/golang.js index 18a299f17..df63bc8bf 100644 --- a/lib/compilers/golang.js +++ b/lib/compilers/golang.js @@ -25,8 +25,8 @@ const Compile = require('../base-compiler'), _ = require('underscore-node'); -function compilenewgol(info, env) { - const compiler = new Compile(info, env); +function compilenewgol(info, env, langId) { + const compiler = new Compile(info, env, langId); compiler.originalGetDefaultExecOptions = compiler.getDefaultExecOptions; function convertNewGoL(code) { @@ -70,7 +70,7 @@ function compilenewgol(info, env) { compiler.getDefaultExecOptions = function () { const execOptions = this.originalGetDefaultExecOptions(); - const goroot = this.env.compilerProps("compiler." + this.compiler.id + ".goroot"); + const goroot = this.compilerProps("compiler." + this.compiler.id + ".goroot"); if (goroot) { execOptions.env.GOROOT = goroot; } diff --git a/lib/compilers/haskell.js b/lib/compilers/haskell.js index a4080192f..78963748e 100644 --- a/lib/compilers/haskell.js +++ b/lib/compilers/haskell.js @@ -1,7 +1,7 @@ var Compile = require('../base-compiler'); -function compileHaskell(info, env) { - var compiler = new Compile(info, env); +function compileHaskell(info, env, langId) { + var compiler = new Compile(info, env, langId); compiler.optionsForFilter = function (filters, outputFilename, userOptions) { return ['-S', '-g', '-o', this.filename(outputFilename)]; }; diff --git a/lib/compilers/ispc.js b/lib/compilers/ispc.js index 3bb0f124f..ff2b8054f 100644 --- a/lib/compilers/ispc.js +++ b/lib/compilers/ispc.js @@ -1,7 +1,7 @@ var Compile = require('../base-compiler'); -function compileISPC(info, env) { - var compiler = new Compile(info, env); +function compileISPC(info, env, langId) { + var compiler = new Compile(info, env, langId); compiler.optionsForFilter = function (filters, outputFilename, userOptions) { return ['--target=sse2-i32x4', '--emit-asm', '-g', '-o', this.filename(outputFilename)]; }; diff --git a/lib/compilers/ldc.js b/lib/compilers/ldc.js index 11de1e66c..ffee8bf95 100644 --- a/lib/compilers/ldc.js +++ b/lib/compilers/ldc.js @@ -25,8 +25,8 @@ var Compile = require('../base-compiler'), argumentParsers = require("./argument-parsers"); -function compileLdc(info, env) { - var compiler = new Compile(info, env); +function compileLdc(info, env, langId) { + var compiler = new Compile(info, env, langId); compiler.compiler.supportsIntel = true; compiler.optionsForFilter = function (filters, outputFilename, userOptions) { var options = ['-g', '-of', this.filename(outputFilename)]; diff --git a/lib/compilers/pascal.js b/lib/compilers/pascal.js index f5855f6cd..e4f0fcbc0 100644 --- a/lib/compilers/pascal.js +++ b/lib/compilers/pascal.js @@ -24,15 +24,14 @@ "use strict"; var Compile = require('../base-compiler'), - logger = require('../logger').logger, PascalDemangler = require('../pascal-support').demangler, utils = require('../utils'), fs = require("fs"), path = require("path"); -function compileFPC(info, env) { +function compileFPC(info, env, langId) { var demangler = new PascalDemangler(); - var compiler = new Compile(info, env); + var compiler = new Compile(info, env, langId); compiler.supportsOptOutput = false; var originalExecBinary = compiler.execBinary; diff --git a/lib/compilers/rust.js b/lib/compilers/rust.js index 6d2295cbe..2fc60fa2b 100644 --- a/lib/compilers/rust.js +++ b/lib/compilers/rust.js @@ -25,8 +25,8 @@ var Compile = require('../base-compiler'), _ = require('underscore-node'); -function compileRust(info, env) { - var compiler = new Compile(info, env); +function compileRust(info, env, langId) { + var compiler = new Compile(info, env, langId); compiler.compiler.supportsIntel = true; compiler.optionsForFilter = function (filters, outputFilename, userOptions) { var options = ['-C', 'debuginfo=1', '-o', this.filename(outputFilename)]; diff --git a/lib/compilers/swift.js b/lib/compilers/swift.js index 884828852..ffd39a295 100644 --- a/lib/compilers/swift.js +++ b/lib/compilers/swift.js @@ -1,8 +1,8 @@ const Compile = require('../base-compiler'), logger = require('../logger').logger; -function compileSwift(info, env) { - const compiler = new Compile(info, env); +function compileSwift(info, env, langId) { + const compiler = new Compile(info, env, langId); compiler.handlePostProcessResult = function (result, postResult) { result.asm = postResult.stdout; diff --git a/lib/languages.js b/lib/languages.js new file mode 100644 index 000000000..258a9b646 --- /dev/null +++ b/lib/languages.js @@ -0,0 +1,116 @@ +// Copyright (c) 2012-2017, Matt Godbolt +// +// 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. +// +// 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 HOLDER 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. + +/* id is what we internally use to identify the language. + *MUST BE* Same as the key so we can always query for it, everywhere. + Used in: properties, url redirect, lang dropdown + name is what we display to the user + Used in: UI + monaco is how we tell the monaco editor which language is this + Used in: Monaco.editor.language + extension is an array for the usual extensions of the language. + The first one declared will be used as the default, else txt + Leading point is needed + Used in: Save to file extension +*/ + +const languages = { + 'c++': { + id: 'c++', + name: 'C++', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'] + }, + cppx: { + id: 'cppx', + name: 'Cppx', + monaco: 'cppp', + extensions: ['.cpp', '.cxx', '.h', '.hpp', '.hxx', '.c'] + }, + c: { + id: 'c', + name: 'C', + monaco: 'c', + extensions: ['.c', '.h'] + }, + rust: { + id: 'rust', + name: 'Rust', + monaco: 'rust', + extensions: ['.rs'] + }, + d: { + id: 'd', + name: 'D', + monaco: 'd', + extensions: ['.d'] + }, + go: { + id: 'go', + name: 'Go', + monaco: 'go', + extensions: ['.go'] + }, + ispc: { + id: 'ispc', + name: 'ispc', + monaco: 'ispc', + extensions: ['.ispc'] + }, + haskell: { + id: 'haskell', + name: 'Haskell', + monaco: 'haskell', + extensions: ['.hs', '.haskell'] + }, + swift: { + id: 'swift', + name: 'Swift', + monaco: 'swift', + extensions: ['.swift'] + }, + pascal: { + id: 'pascal', + name: 'Pascal', + monaco: 'pascal', + extensions: ['.pas'] + } +}; + +const fs = require('fs-extra'); +const _ = require('underscore-node'); +const path = require('path'); +_.each(languages, lang => { + try { + const example = fs.readFileSync(path.join('examples', lang.id, 'default' + lang.extensions[0]), 'utf8'); + lang.example = example; + } catch (error) { + lang.example = "Oops, something went wrong and we could not get the default code for this language."; + } +}); + +module.exports = { + list: languages +}; diff --git a/lib/sources/builtin.js b/lib/sources/builtin.js index d5252bc05..aaf78b3be 100644 --- a/lib/sources/builtin.js +++ b/lib/sources/builtin.js @@ -24,27 +24,31 @@ const props = require('../properties.js'), path = require('path'), - fs = require('fs'); + fs = require('fs'), + _ = require('underscore-node'); +const basePath = props.get('builtin', 'sourcePath', './examples/'); +const replacer = new RegExp('_', 'g'); +const examples = _.flatten( + fs.readdirSync(basePath) + .map(folder => { + const folerPath = path.join(basePath, folder); + return fs.readdirSync(folerPath) + .map(file => { + const filePath = path.join(folerPath, file); + const fileName = path.parse(file).name; + return {lang: folder, name: fileName.replace(replacer, ' '), path: filePath, file: fileName}; + }) + .filter(descriptor => descriptor.name !== "default") + .sort((x, y) => x.name.localeCompare(y.name)); + })); -const sourcePath = props.get('builtin', 'sourcepath', './examples/c++'); -const sourceMatch = new RegExp(props.get('builtin', 'extensionRe', '.*\\.cpp$')); -const examples = fs.readdirSync(sourcePath) - .filter(file => file.match(sourceMatch)) - .map(file => { - const nicename = file.replace(/\.cpp$/, ''); - return {urlpart: nicename, name: nicename.replace(/_/g, ' '), path: path.join(sourcePath, file)}; - }).sort((x, y) => x.name.localeCompare(y.name)); - -const byUrlpart = {}; -examples.forEach(e => byUrlpart[e.urlpart] = e.path); - -function load(filename) { - const path = byUrlpart[filename]; - if (!path) { +function load(lang, filename) { + const example = _.find(examples, example => example.lang === lang && example.file === filename); + if (!example) { return Promise.reject("No such path"); } return new Promise((resolve, reject) => { - fs.readFile(path, 'utf-8', function (err, res) { + fs.readFile(example.path, 'utf-8', (err, res) => { if (err) { reject(err); } else { @@ -55,7 +59,9 @@ function load(filename) { } function list() { - return Promise.resolve(examples.map(example => ({urlpart: example.urlpart, name: example.name}))); + return Promise.resolve(examples.map(example => { + return {file: example.file, name: example.name, lang: example.lang}; + })); } module.exports.load = load; |