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

Commit e6bcf22

Browse files
committed
fix(build): check to ensure tsconfig contains sourcemaps true.
1 parent 3a05ac0 commit e6bcf22

File tree

3 files changed

+205
-69
lines changed

3 files changed

+205
-69
lines changed

src/build.spec.ts

Lines changed: 150 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ import * as transpile from './transpile';
1414
describe('build', () => {
1515
beforeEach(() => {
1616
spyOn(clean, 'clean');
17-
spyOn(helpers, 'readFileAsync').and.returnValue(Promise.resolve());
17+
spyOn(helpers, 'readFileAsync').and.callFake(() => {
18+
return Promise.resolve(`{
19+
"compilerOptions": {
20+
"sourceMap": true
21+
}
22+
}
23+
`);
24+
});
1825
spyOn(copy, 'copy').and.returnValue(Promise.resolve());
1926
spyOn(ngc, 'ngc').and.returnValue(Promise.resolve());
2027
spyOn(bundle, 'bundle').and.returnValue(Promise.resolve());
@@ -26,56 +33,150 @@ describe('build', () => {
2633
});
2734

2835
it('should do a prod build', () => {
29-
let context: BuildContext = {
30-
isProd: true,
31-
optimizeJs: true,
32-
runMinifyJs: true,
33-
runMinifyCss: true,
34-
runAot: true
35-
};
36-
37-
return build.build(context).then(() => {
38-
expect(helpers.readFileAsync).toHaveBeenCalled();
39-
expect(copy.copy).toHaveBeenCalled();
40-
expect(ngc.ngc).toHaveBeenCalled();
41-
expect(bundle.bundle).toHaveBeenCalled();
42-
expect(minify.minifyJs).toHaveBeenCalled();
43-
expect(sass.sass).toHaveBeenCalled();
44-
expect(minify.minifyCss).toHaveBeenCalled();
45-
expect(lint.lint).toHaveBeenCalled();
46-
47-
expect(transpile.transpile).not.toHaveBeenCalled();
48-
}).catch(err => {
49-
console.log(`err.message: `, err.message);
50-
expect(true).toEqual(false);
51-
});
36+
let context: BuildContext = {
37+
isProd: true,
38+
optimizeJs: true,
39+
runMinifyJs: true,
40+
runMinifyCss: true,
41+
runAot: true
42+
};
43+
44+
return build.build(context).then(() => {
45+
expect(helpers.readFileAsync).toHaveBeenCalled();
46+
expect(copy.copy).toHaveBeenCalled();
47+
expect(ngc.ngc).toHaveBeenCalled();
48+
expect(bundle.bundle).toHaveBeenCalled();
49+
expect(minify.minifyJs).toHaveBeenCalled();
50+
expect(sass.sass).toHaveBeenCalled();
51+
expect(minify.minifyCss).toHaveBeenCalled();
52+
expect(lint.lint).toHaveBeenCalled();
53+
54+
expect(transpile.transpile).not.toHaveBeenCalled();
55+
}).catch(err => {
56+
console.log(`err.message: `, err.message);
57+
expect(true).toEqual(false);
58+
});
59+
});
60+
61+
it('should do a dev build', () => {
62+
let context: BuildContext = {
63+
isProd: false,
64+
optimizeJs: false,
65+
runMinifyJs: false,
66+
runMinifyCss: false,
67+
runAot: false
68+
};
69+
70+
return build.build(context).then(() => {
71+
expect(helpers.readFileAsync).toHaveBeenCalled();
72+
expect(copy.copy).toHaveBeenCalled();
73+
expect(transpile.transpile).toHaveBeenCalled();
74+
expect(bundle.bundle).toHaveBeenCalled();
75+
expect(sass.sass).toHaveBeenCalled();
76+
expect(lint.lint).toHaveBeenCalled();
77+
78+
expect(ngc.ngc).not.toHaveBeenCalled();
79+
expect(minify.minifyJs).not.toHaveBeenCalled();
80+
expect(minify.minifyCss).not.toHaveBeenCalled();
81+
}).catch(err => {
82+
console.log(`err.message: `, err.message);
83+
expect(true).toEqual(false);
84+
});
85+
});
86+
});
87+
88+
describe('test project requirements before building', () => {
89+
it('should fail if APP_ENTRY_POINT file does not exist', () => {
90+
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
91+
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
92+
const error = new Error('App entry point was not found');
93+
94+
spyOn(helpers, 'readFileAsync').and.returnValue(Promise.reject(error));
95+
96+
return build.build({}).catch((e) => {
97+
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
98+
expect(e).toEqual(error);
5299
});
100+
});
101+
102+
it('should fail if IONIC_TS_CONFIG file does not exist', () => {
103+
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
104+
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
105+
const error = new Error('App entry point was not found');
53106

54-
it('should do a dev build', (done: Function) => {
55-
let context: BuildContext = {
56-
isProd: false,
57-
optimizeJs: false,
58-
runMinifyJs: false,
59-
runMinifyCss: false,
60-
runAot: false
61-
};
62-
63-
build.build(context).then(() => {
64-
expect(helpers.readFileAsync).toHaveBeenCalled();
65-
expect(copy.copy).toHaveBeenCalled();
66-
expect(transpile.transpile).toHaveBeenCalled();
67-
expect(bundle.bundle).toHaveBeenCalled();
68-
expect(sass.sass).toHaveBeenCalled();
69-
expect(lint.lint).toHaveBeenCalled();
70-
71-
expect(ngc.ngc).not.toHaveBeenCalled();
72-
expect(minify.minifyJs).not.toHaveBeenCalled();
73-
expect(minify.minifyCss).not.toHaveBeenCalled();
74-
done();
75-
}).catch(err => {
76-
console.log(`err.message: `, err.message);
77-
expect(true).toEqual(false);
78-
});
107+
spyOn(helpers, 'readFileAsync').and.callFake((filePath: string) => {
108+
if (filePath === 'src/app/main.ts') {
109+
return Promise.resolve('allgood');
110+
}
111+
return Promise.reject(error);
79112
});
80113

114+
return build.build({}).catch((e) => {
115+
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
116+
expect(e).toEqual(error);
117+
});
118+
});
119+
120+
it('should fail fataly if IONIC_TS_CONFIG file does not contain valid JSON', () => {
121+
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
122+
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
123+
spyOn(helpers, 'readFileAsync').and.callFake(() => {
124+
return Promise.resolve(`{
125+
"compilerOptions" {
126+
"sourceMap": false
127+
}
128+
}
129+
`);
130+
});
131+
132+
return build.build({}).catch((e) => {
133+
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
134+
expect(e.isFatal).toBeTruthy();
135+
});
136+
});
137+
138+
it('should fail fataly if IONIC_TS_CONFIG file does not contain compilerOptions.sourceMap === true', () => {
139+
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
140+
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
141+
spyOn(helpers, 'readFileAsync').and.callFake(() => {
142+
return Promise.resolve(`{
143+
"compilerOptions": {
144+
"sourceMap": false
145+
}
146+
}
147+
`);
148+
});
149+
150+
return build.build({}).catch((e) => {
151+
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
152+
expect(e.isFatal).toBeTruthy();
153+
});
154+
});
155+
156+
it('should succeed if IONIC_TS_CONFIG file contains compilerOptions.sourceMap === true', () => {
157+
process.env.IONIC_APP_ENTRY_POINT = 'src/app/main.ts';
158+
process.env.IONIC_TS_CONFIG = 'tsConfig.js';
159+
160+
spyOn(clean, 'clean');
161+
spyOn(copy, 'copy').and.returnValue(Promise.resolve());
162+
spyOn(ngc, 'ngc').and.returnValue(Promise.resolve());
163+
spyOn(bundle, 'bundle').and.returnValue(Promise.resolve());
164+
spyOn(minify, 'minifyJs').and.returnValue(Promise.resolve());
165+
spyOn(sass, 'sass').and.returnValue(Promise.resolve());
166+
spyOn(minify, 'minifyCss').and.returnValue(Promise.resolve());
167+
spyOn(lint, 'lint').and.returnValue(Promise.resolve());
168+
spyOn(transpile, 'transpile').and.returnValue(Promise.resolve());
169+
spyOn(helpers, 'readFileAsync').and.callFake(() => {
170+
return Promise.resolve(`{
171+
"compilerOptions": {
172+
"sourceMap": true
173+
}
174+
}
175+
`);
176+
});
177+
178+
return build.build({}).then(() => {
179+
expect(helpers.readFileAsync).toHaveBeenCalledTimes(2);
180+
});
181+
});
81182
});

src/build.ts

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,71 @@ export function build(context: BuildContext) {
2424
logger.finish();
2525
})
2626
.catch(err => {
27-
handleDeprecations(err);
27+
if (err.isFatal) { throw err; }
2828
throw logger.fail(err);
2929
});
3030
}
3131

32-
function handleDeprecations(error: Error) {
33-
if (error && error.message && error.message.indexOf('ENOENT') >= 0 && error.message.indexOf(process.env.IONIC_APP_ENTRY_POINT)) {
34-
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.
35-
For more information, please see the default Ionic project main.ts file here:
36-
https://github.com/driftyco/ionic2-app-base/tree/master/src/app/main.ts`);
37-
error.isFatal = true;
38-
throw error;
39-
}
40-
}
41-
42-
4332
function buildWorker(context: BuildContext) {
4433
return Promise.resolve().then(() => {
4534
// load any 100% required files to ensure they exist
4635
return validateRequiredFilesExist();
47-
}).then(() => {
36+
})
37+
.then(([appEntryPointContents, tsConfigContents]) => {
38+
return validateTsConfigSettings(tsConfigContents);
39+
})
40+
.then(() => {
4841
return buildProject(context);
4942
});
5043
}
5144

5245
function validateRequiredFilesExist() {
53-
// for now, just do the entry point
54-
// eventually this could be Promise.all and load a bunch of stuff
55-
return readFileAsync(process.env.IONIC_APP_ENTRY_POINT);
46+
return Promise.all([
47+
readFileAsync(process.env.IONIC_APP_ENTRY_POINT),
48+
readFileAsync(process.env.IONIC_TS_CONFIG)
49+
]).catch((error) => {
50+
if (error.code === 'ENOENT' && error.path === process.env.IONIC_APP_ENTRY_POINT) {
51+
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.
52+
For more information, please see the default Ionic project main.ts file here:
53+
https://github.com/driftyco/ionic2-app-base/tree/master/src/app/main.ts`);
54+
error.isFatal = true;
55+
throw error;
56+
}
57+
if (error.code === 'ENOENT' && error.path === process.env.IONIC_TS_CONFIG) {
58+
error = new BuildError(['You are missing a "tsconfig.json" file. This file is required.',
59+
'For more information please see the default Ionic project tsconfig.json file here:',
60+
'https://github.com/driftyco/ionic2-app-base/blob/master/tsconfig.json'].join('\n'));
61+
error.isFatal = true;
62+
throw error;
63+
}
64+
error.isFatal = true;
65+
throw error;
66+
});
67+
}
68+
69+
function validateTsConfigSettings(tsConfigFileContents: string) {
70+
71+
return new Promise((resolve, reject) => {
72+
try {
73+
const tsConfigJson = JSON.parse(tsConfigFileContents);
74+
const isValid = tsConfigJson.hasOwnProperty('compilerOptions') &&
75+
tsConfigJson.compilerOptions.hasOwnProperty('sourceMap') &&
76+
tsConfigJson.compilerOptions.sourceMap === true;
77+
78+
if (!isValid) {
79+
const error = new BuildError(['Your "tsconfig.json" file must have compilerOptions.sourceMap set to true.',
80+
'For more information please see the default Ionic project tsconfig.json file here:',
81+
'https://github.com/driftyco/ionic2-app-base/blob/master/tsconfig.json'].join('\n'));
82+
error.isFatal = true;
83+
return reject(error);
84+
}
85+
resolve();
86+
} catch (e) {
87+
const error = new BuildError('Your "tsconfig.json" file contains malformed JSON.');
88+
error.isFatal = true;
89+
return reject(error);
90+
}
91+
});
5692
}
5793

5894
function buildProject(context: BuildContext) {

src/util/helpers.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { basename, dirname, extname, join } from 'path';
22
import { BuildContext, File } from './interfaces';
3-
import { BuildError } from './errors';
43
import { createReadStream, createWriteStream, readFile, readFileSync, readJsonSync, remove, unlink, writeFile } from 'fs-extra';
54
import * as osName from 'os-name';
65

@@ -98,7 +97,7 @@ export function writeFileAsync(filePath: string, content: string): Promise<any>
9897
return new Promise((resolve, reject) => {
9998
writeFile(filePath, content, (err) => {
10099
if (err) {
101-
return reject(new BuildError(err));
100+
return reject(err);
102101
}
103102
return resolve();
104103
});
@@ -109,7 +108,7 @@ export function readFileAsync(filePath: string): Promise<string> {
109108
return new Promise((resolve, reject) => {
110109
readFile(filePath, 'utf-8', (err, buffer) => {
111110
if (err) {
112-
return reject(new BuildError(err));
111+
return reject(err);
113112
}
114113
return resolve(buffer);
115114
});
@@ -120,7 +119,7 @@ export function unlinkAsync(filePath: string): Promise<any> {
120119
return new Promise((resolve, reject) => {
121120
unlink(filePath, (err: Error) => {
122121
if (err) {
123-
return reject(new BuildError(err));
122+
return reject(err);
124123
}
125124
return resolve();
126125
});

0 commit comments

Comments
 (0)