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

Commit

Permalink
fix(build): check to ensure tsconfig contains sourcemaps true.
Browse files Browse the repository at this point in the history
  • Loading branch information
jthoms1 committed Dec 20, 2016
1 parent 3a05ac0 commit e6bcf22
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 69 deletions.
199 changes: 150 additions & 49 deletions src/build.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ import * as transpile from './transpile';
describe('build', () => {
beforeEach(() => {
spyOn(clean, 'clean');
spyOn(helpers, 'readFileAsync').and.returnValue(Promise.resolve());
spyOn(helpers, 'readFileAsync').and.callFake(() => {
return Promise.resolve(`{
"compilerOptions": {
"sourceMap": true
}
}
`);
});
spyOn(copy, 'copy').and.returnValue(Promise.resolve());
spyOn(ngc, 'ngc').and.returnValue(Promise.resolve());
spyOn(bundle, 'bundle').and.returnValue(Promise.resolve());
Expand All @@ -26,56 +33,150 @@ describe('build', () => {
});

it('should do a prod build', () => {
let context: BuildContext = {
isProd: true,
optimizeJs: true,
runMinifyJs: true,
runMinifyCss: true,
runAot: true
};

return build.build(context).then(() => {
expect(helpers.readFileAsync).toHaveBeenCalled();
expect(copy.copy).toHaveBeenCalled();
expect(ngc.ngc).toHaveBeenCalled();
expect(bundle.bundle).toHaveBeenCalled();
expect(minify.minifyJs).toHaveBeenCalled();
expect(sass.sass).toHaveBeenCalled();
expect(minify.minifyCss).toHaveBeenCalled();
expect(lint.lint).toHaveBeenCalled();

expect(transpile.transpile).not.toHaveBeenCalled();
}).catch(err => {
console.log(`err.message: `, err.message);
expect(true).toEqual(false);
});
let context: BuildContext = {
isProd: true,
optimizeJs: true,
runMinifyJs: true,
runMinifyCss: true,
runAot: true
};

return build.build(context).then(() => {
expect(helpers.readFileAsync).toHaveBeenCalled();
expect(copy.copy).toHaveBeenCalled();
expect(ngc.ngc).toHaveBeenCalled();
expect(bundle.bundle).toHaveBeenCalled();
expect(minify.minifyJs).toHaveBeenCalled();
expect(sass.sass).toHaveBeenCalled();
expect(minify.minifyCss).toHaveBeenCalled();
expect(lint.lint).toHaveBeenCalled();

expect(transpile.transpile).not.toHaveBeenCalled();
}).catch(err => {
console.log(`err.message: `, err.message);
expect(true).toEqual(false);
});
});

it('should do a dev build', () => {
let context: BuildContext = {
isProd: false,
optimizeJs: false,
runMinifyJs: false,
runMinifyCss: false,
runAot: false
};

return build.build(context).then(() => {
expect(helpers.readFileAsync).toHaveBeenCalled();
expect(copy.copy).toHaveBeenCalled();
expect(transpile.transpile).toHaveBeenCalled();
expect(bundle.bundle).toHaveBeenCalled();
expect(sass.sass).toHaveBeenCalled();
expect(lint.lint).toHaveBeenCalled();

expect(ngc.ngc).not.toHaveBeenCalled();
expect(minify.minifyJs).not.toHaveBeenCalled();
expect(minify.minifyCss).not.toHaveBeenCalled();
}).catch(err => {
console.log(`err.message: `, err.message);
expect(true).toEqual(false);
});
});
});

describe('test project requirements before building', () => {
it('should fail if APP_ENTRY_POINT file does not exist', () => {
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
const error = new Error('App entry point was not found');

spyOn(helpers, 'readFileAsync').and.returnValue(Promise.reject(error));

return build.build({}).catch((e) => {
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
expect(e).toEqual(error);
});
});

it('should fail if IONIC_TS_CONFIG file does not exist', () => {
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
const error = new Error('App entry point was not found');

it('should do a dev build', (done: Function) => {
let context: BuildContext = {
isProd: false,
optimizeJs: false,
runMinifyJs: false,
runMinifyCss: false,
runAot: false
};

build.build(context).then(() => {
expect(helpers.readFileAsync).toHaveBeenCalled();
expect(copy.copy).toHaveBeenCalled();
expect(transpile.transpile).toHaveBeenCalled();
expect(bundle.bundle).toHaveBeenCalled();
expect(sass.sass).toHaveBeenCalled();
expect(lint.lint).toHaveBeenCalled();

expect(ngc.ngc).not.toHaveBeenCalled();
expect(minify.minifyJs).not.toHaveBeenCalled();
expect(minify.minifyCss).not.toHaveBeenCalled();
done();
}).catch(err => {
console.log(`err.message: `, err.message);
expect(true).toEqual(false);
});
spyOn(helpers, 'readFileAsync').and.callFake((filePath: string) => {
if (filePath === 'src/app/main.ts') {
return Promise.resolve('allgood');
}
return Promise.reject(error);
});

return build.build({}).catch((e) => {
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
expect(e).toEqual(error);
});
});

it('should fail fataly if IONIC_TS_CONFIG file does not contain valid JSON', () => {
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
spyOn(helpers, 'readFileAsync').and.callFake(() => {
return Promise.resolve(`{
"compilerOptions" {
"sourceMap": false
}
}
`);
});

return build.build({}).catch((e) => {
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
expect(e.isFatal).toBeTruthy();
});
});

it('should fail fataly if IONIC_TS_CONFIG file does not contain compilerOptions.sourceMap === true', () => {
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
spyOn(helpers, 'readFileAsync').and.callFake(() => {
return Promise.resolve(`{
"compilerOptions": {
"sourceMap": false
}
}
`);
});

return build.build({}).catch((e) => {
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
expect(e.isFatal).toBeTruthy();
});
});

it('should succeed if IONIC_TS_CONFIG file contains compilerOptions.sourceMap === true', () => {
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
process.env.IONIC_TS_CONFIG = 'tsConfig.js';

spyOn(clean, 'clean');
spyOn(copy, 'copy').and.returnValue(Promise.resolve());
spyOn(ngc, 'ngc').and.returnValue(Promise.resolve());
spyOn(bundle, 'bundle').and.returnValue(Promise.resolve());
spyOn(minify, 'minifyJs').and.returnValue(Promise.resolve());
spyOn(sass, 'sass').and.returnValue(Promise.resolve());
spyOn(minify, 'minifyCss').and.returnValue(Promise.resolve());
spyOn(lint, 'lint').and.returnValue(Promise.resolve());
spyOn(transpile, 'transpile').and.returnValue(Promise.resolve());
spyOn(helpers, 'readFileAsync').and.callFake(() => {
return Promise.resolve(`{
"compilerOptions": {
"sourceMap": true
}
}
`);
});

return build.build({}).then(() => {
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
});
});
});
68 changes: 52 additions & 16 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,71 @@ export function build(context: BuildContext) {
logger.finish();
})
.catch(err => {
handleDeprecations(err);
if (err.isFatal) { throw err; }
throw logger.fail(err);
});
}

function handleDeprecations(error: Error) {
if (error && error.message && error.message.indexOf('ENOENT') >= 0 && error.message.indexOf(process.env.IONIC_APP_ENTRY_POINT)) {
const error = new BuildError(`"main.dev.ts" and "main.prod.ts" have been deprecated. Please create a new file "main.ts" containing the content of "main.dev.ts", and then delete the deprecated files.
For more information, please see the default Ionic project main.ts file here:
https://github.com/driftyco/ionic2-app-base/tree/master/src/app/main.ts`);
error.isFatal = true;
throw error;
}
}


function buildWorker(context: BuildContext) {
return Promise.resolve().then(() => {
// load any 100% required files to ensure they exist
return validateRequiredFilesExist();
}).then(() => {
})
.then(([appEntryPointContents, tsConfigContents]) => {
return validateTsConfigSettings(tsConfigContents);
})
.then(() => {
return buildProject(context);
});
}

function validateRequiredFilesExist() {
// for now, just do the entry point
// eventually this could be Promise.all and load a bunch of stuff
return readFileAsync(process.env.IONIC_APP_ENTRY_POINT);
return Promise.all([
readFileAsync(process.env.IONIC_APP_ENTRY_POINT),
readFileAsync(process.env.IONIC_TS_CONFIG)
]).catch((error) => {
if (error.code === 'ENOENT' && error.path === process.env.IONIC_APP_ENTRY_POINT) {
error = new BuildError(`"main.dev.ts" and "main.prod.ts" have been deprecated. Please create a new file "main.ts" containing the content of "main.dev.ts", and then delete the deprecated files.
For more information, please see the default Ionic project main.ts file here:
https://github.com/driftyco/ionic2-app-base/tree/master/src/app/main.ts`);
error.isFatal = true;
throw error;
}
if (error.code === 'ENOENT' && error.path === process.env.IONIC_TS_CONFIG) {
error = new BuildError(['You are missing a "tsconfig.json" file. This file is required.',
'For more information please see the default Ionic project tsconfig.json file here:',
'https://github.com/driftyco/ionic2-app-base/blob/master/tsconfig.json'].join('\n'));
error.isFatal = true;
throw error;
}
error.isFatal = true;
throw error;
});
}

function validateTsConfigSettings(tsConfigFileContents: string) {

return new Promise((resolve, reject) => {
try {
const tsConfigJson = JSON.parse(tsConfigFileContents);
const isValid = tsConfigJson.hasOwnProperty('compilerOptions') &&
tsConfigJson.compilerOptions.hasOwnProperty('sourceMap') &&
tsConfigJson.compilerOptions.sourceMap === true;

if (!isValid) {
const error = new BuildError(['Your "tsconfig.json" file must have compilerOptions.sourceMap set to true.',
'For more information please see the default Ionic project tsconfig.json file here:',
'https://github.com/driftyco/ionic2-app-base/blob/master/tsconfig.json'].join('\n'));
error.isFatal = true;
return reject(error);
}
resolve();
} catch (e) {
const error = new BuildError('Your "tsconfig.json" file contains malformed JSON.');
error.isFatal = true;
return reject(error);
}
});
}

function buildProject(context: BuildContext) {
Expand Down
7 changes: 3 additions & 4 deletions src/util/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { basename, dirname, extname, join } from 'path';
import { BuildContext, File } from './interfaces';
import { BuildError } from './errors';
import { createReadStream, createWriteStream, readFile, readFileSync, readJsonSync, remove, unlink, writeFile } from 'fs-extra';
import * as osName from 'os-name';

Expand Down Expand Up @@ -98,7 +97,7 @@ export function writeFileAsync(filePath: string, content: string): Promise<any>
return new Promise((resolve, reject) => {
writeFile(filePath, content, (err) => {
if (err) {
return reject(new BuildError(err));
return reject(err);
}
return resolve();
});
Expand All @@ -109,7 +108,7 @@ export function readFileAsync(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
readFile(filePath, 'utf-8', (err, buffer) => {
if (err) {
return reject(new BuildError(err));
return reject(err);
}
return resolve(buffer);
});
Expand All @@ -120,7 +119,7 @@ export function unlinkAsync(filePath: string): Promise<any> {
return new Promise((resolve, reject) => {
unlink(filePath, (err: Error) => {
if (err) {
return reject(new BuildError(err));
return reject(err);
}
return resolve();
});
Expand Down

0 comments on commit e6bcf22

Please sign in to comment.