Skip to content
This repository has been archived by the owner on Oct 1, 2020. It is now read-only.

Commit

Permalink
Merge pull request #47 from electronjs/configuration
Browse files Browse the repository at this point in the history
Parse configuration files
  • Loading branch information
anaisbetts committed Dec 28, 2015
2 parents bddc580 + b1c1bb0 commit 3b8c2bb
Show file tree
Hide file tree
Showing 10 changed files with 454 additions and 55 deletions.
1 change: 1 addition & 0 deletions src/compiler-host.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export default class CompilerHost {

let dependentFiles = await compiler.determineDependentFiles(code, filePath, ctx);

d(`Using compiler options: ${JSON.stringify(compiler.compilerOptions)}`);
let result = await compiler.compile(code, filePath, ctx);

let shouldInlineHtmlify =
Expand Down
214 changes: 214 additions & 0 deletions src/config-parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import _ from 'lodash';
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import pify from 'pify';

import FileChangedCache from './file-change-cache';
import CompilerHost from './compiler-host';

const pfs = pify(fs);
const d = require('debug')('electron-compile:config-parser');

// NB: We intentionally delay-load this so that in production, you can create
// cache-only versions of these compilers
let allCompilerClasses = null;

export function createCompilerHostFromConfiguration(info) {
let compilers = createCompilers();
let rootCacheDir = info.rootCacheDir || calculateDefaultCompileCacheDirectory();

let fileChangeCache = new FileChangedCache(info.appRoot);
let ret = new CompilerHost(rootCacheDir, compilers, fileChangeCache, false, compilers['text/plain']);

_.each(Object.keys(info.options || {}), (x) => {
let opts = info.options[x];
if (!(x in compilers)) {
throw new Error(`Found compiler settings for missing compiler: ${x}`);
}

d(`Setting options for ${x}: ${JSON.stringify(opts)}`);
compilers[x].compilerOptions = opts;
});

d(`Created compiler host with options: ${JSON.stringify(info)}`);
return ret;
}

export async function createCompilerHostFromBabelRc(file) {
let info = JSON.parse(await pfs.readFile(file, 'utf8'));

// project.json
if ('babel' in info) {
info = info.babel;
}

if ('env' in info) {
let ourEnv = process.env.BABEL_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}

// Are we still project.json (i.e. is there no babel info whatsoever?)
if ('name' in info && 'version' in info) {
return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: getDefaultConfiguration()
});
}

return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: {
'text/javascript': info
}
});
}

export async function createCompilerHostFromConfigFile(file) {
let info = JSON.parse(await pfs.readFile(file, 'utf8'));

if ('env' in info) {
let ourEnv = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}

return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: info
});
}

export async function createCompilerHostFromProjectRoot(rootDir) {
let compilerc = path.join(rootDir, '.compilerc');
if (await pfs.exists(compilerc)) {
return createCompilerHostFromConfigFile(compilerc);
}

let babelrc = path.join(rootDir, '.babelrc');
if (await pfs.exists(compilerc)) {
return createCompilerHostFromBabelRc(babelrc);
}

return createCompilerHostFromBabelRc(path.join(rootDir, 'project.json'));
}

export function createCompilerHostFromBabelRcSync(file) {
let info = JSON.parse(fs.readFileSync(file, 'utf8'));

// project.json
if ('babel' in info) {
info = info.babel;
}

if ('env' in info) {
let ourEnv = process.env.BABEL_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}

// Are we still project.json (i.e. is there no babel info whatsoever?)
if ('name' in info && 'version' in info) {
return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: getDefaultConfiguration()
});
}

return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: {
'text/javascript': info
}
});
}

export function createCompilerHostFromConfigFileSync(file) {
let info = JSON.parse(fs.readFileSync(file, 'utf8'));

if ('env' in info) {
let ourEnv = process.env.ELECTRON_COMPILE_ENV || process.env.NODE_ENV || 'development';
info = info.env[ourEnv];
}

return createCompilerHostFromConfiguration({
appRoot: path.dirname(file),
options: info
});
}

export function createCompilerHostFromProjectRootSync(rootDir) {
let compilerc = path.join(rootDir, '.compilerc');
if (fs.existsSync(compilerc)) {
return createCompilerHostFromConfigFile(compilerc);
}

let babelrc = path.join(rootDir, '.babelrc');
if (fs.existsSync(compilerc)) {
return createCompilerHostFromBabelRc(babelrc);
}

return createCompilerHostFromBabelRc(path.join(rootDir, 'project.json'));
}

export function calculateDefaultCompileCacheDirectory() {
let tmpDir = process.env.TEMP || process.env.TMPDIR || '/tmp';
let hash = require('crypto').createHash('md5').update(process.execPath).digest('hex');

let cacheDir = path.join(tmpDir, `compileCache_${hash}`);
mkdirp.sync(cacheDir);

d(`Using default cache directory: ${cacheDir}`);
return cacheDir;
}

export function getDefaultConfiguration() {
return {
'text/javascript': {
"presets": ["stage-0", "es2015"],
"sourceMaps": "inline"
}
};
}

// Public: Allows you to create new instances of all compilers that are
// supported by electron-compile and use them directly. Currently supports
// Babel, CoffeeScript, TypeScript, LESS, and Sass/SCSS.
//
// Returns an {Object} whose Keys are MIME types, and whose values are objects
// which conform to {CompilerBase}.
export function createCompilers() {
if (!allCompilerClasses) {
// First we want to see if electron-compilers itself has been installed with
// devDependencies. If that's not the case, check to see if
// electron-compilers is installed as a peer dependency (probably as a
// devDependency of the root project).
const locations = ['electron-compilers', '../../electron-compilers'];

for (let location of locations) {
try {
allCompilerClasses = require(location);
} catch (e) {
// Yolo
}
}

if (!allCompilerClasses) {
throw new Error("Electron compilers not found but were requested to be loaded");
}
}

let ret = {};
let instantiatedClasses = _.map(allCompilerClasses, (Klass) => {
if ('createFromCompilers' in Klass) {
return Klass.createFromCompilers(ret);
} else {
return new Klass();
}
});

return _.reduce(instantiatedClasses, (acc,x) => {
let Klass = Object.getPrototypeOf(x).constructor;

for (let type of Klass.getInputMimeTypes()) { acc[type] = x; }
return acc;
}, {});
}
2 changes: 1 addition & 1 deletion src/file-change-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default class FileChangedCache {
};

this.changeCache[cacheKey] = { ctime, size, info };
d(`Cache entry for ${cacheKey}: ${this.changeCache[cacheKey]}`);
d(`Cache entry for ${cacheKey}: ${JSON.stringify(this.changeCache[cacheKey])}`);

if (binaryData) {
return _.extend({binaryData}, info);
Expand Down
16 changes: 14 additions & 2 deletions test/compiler-host.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import './support.js';

import _ from 'lodash';
import path from 'path';
import fs from 'fs';
import rimraf from 'rimraf';
import mkdirp from 'mkdirp';
import FileChangeCache from '../lib/file-change-cache';
import CompilerHost from '../lib/compiler-host';

const d = require('debug')('electron-test:compiler-host');
const d = require('debug')('test:compiler-host');

let testCount=0;

Expand Down Expand Up @@ -36,7 +37,18 @@ describe('The compiler host', function() {
afterEach(function() {
rimraf.sync(this.tempCacheDir);
});


it('should compile basic HTML and not blow up', function() {
let input = '<html><style type="text/less">body { font-family: "lol"; }</style></html>';
let inFile = path.join(this.tempCacheDir, 'input.html');
fs.writeFileSync(inFile, input);

let result = this.fixture.compileSync(inFile);

expect(result.mimeType).to.equal('text/html');
expect(result.code.length > input.length).to.be.ok;
});

it('Should compile everything in the fixtures directory', async function() {
let input = path.join(__dirname, '..', 'test', 'fixtures');

Expand Down
Loading

0 comments on commit 3b8c2bb

Please sign in to comment.