Skip to content

Commit 8365821

Browse files
Open editor on clicking compilation error
1 parent 3371e52 commit 8365821

6 files changed

Lines changed: 687 additions & 439 deletions

File tree

lib/templates/error.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,9 @@
10871087
<article class="content">
10881088
<h1 class="error-header">Dang! Looks like a {{errorType}}.</h1>
10891089
{{#if location.file}}
1090-
<h2 class="error-message">{{location.file}}{{#if location.line}}:{{location.line}}{{/if}}</h2>
1090+
<h2 class="error-message" onclick="openEditorForTemplateError('/ember_open_editor_for_template_compilation_error')">
1091+
{{location.file}}{{#if location.line}}:{{location.line}}{{/if}}
1092+
</h2>
10911093
{{/if}}
10921094

10931095
{{#if codeFrame}}
@@ -1125,5 +1127,12 @@ <h2>Environment</h2>
11251127
<span>{{versionString}}</span>
11261128
</article>
11271129
</main>
1130+
<script>
1131+
function openEditorForTemplateError(fileName) {
1132+
let xhr = new XMLHttpRequest();
1133+
xhr.open('GET', fileName, true);
1134+
xhr.send();
1135+
}
1136+
</script>
11281137
</body>
11291138
</html>

lib/utils/filename-normaliser.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const { existsSync } = require('fs');
5+
6+
const pkg = require(`${process.cwd()}/package.json`);
7+
8+
const normaliseFileName = (fileName) => {
9+
// handles module unification layout
10+
// location as per stack : src/ui/components/my-component/template.hbs
11+
// should be normalised to: src/ui/components/my-component/template.hbs
12+
if (fileName.startsWith('src')) {
13+
return fileName;
14+
}
15+
16+
// handle templates inside application with either pod or classic structure
17+
// Classic Structure
18+
// location as per stack : project-name/templates/templateName.hbs
19+
// should be normalised to: app/templates/templateName.hbs
20+
// Pods
21+
// location as per stack : project-name/routeName/templateName.hbs
22+
// should be normalised to: app/routeName/templateName.hbs
23+
if (fileName.startsWith(pkg.name)) {
24+
let fileNameElements = fileName.split(path.sep);
25+
fileNameElements.shift();
26+
27+
return path.join('app', ...fileNameElements);
28+
}
29+
30+
// handle templates inside in-repo engines
31+
// location as per stack : engine-name/templates/cars.hbs
32+
// should be normalised to: lib/engine-name/addon/templates/templateName.hbs
33+
let fileNameElements = fileName.split(path.sep);
34+
fileNameElements = ['lib', fileNameElements.shift(), 'addon', ...fileNameElements];
35+
36+
return path.join(...fileNameElements);
37+
};
38+
39+
const getNormalisedFileName = (fileName, line = 1, column = 1) => {
40+
let normalisedFileName = normaliseFileName(fileName);
41+
if (existsSync(normalisedFileName)) {
42+
return `${normalisedFileName}:${line}:${column}`;
43+
}
44+
45+
return null;
46+
}
47+
48+
module.exports = { normaliseFileName, getNormalisedFileName };

lib/watcher-middleware.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
const url = require('url');
44
const path = require('path');
5+
const launchEditor = require('launch-editor');
56

67
const errorHandler = require('./utils/error-handler');
8+
const { getNormalisedFileName } = require('./utils/filename-normaliser');
79

810
module.exports = function watcherMiddleware(watcher, options) {
911
options = options || {};
@@ -34,6 +36,28 @@ module.exports = function watcherMiddleware(watcher, options) {
3436

3537
next();
3638
}, (buildError) => {
39+
if (request.url === '/ember_open_editor_for_template_compilation_error') {
40+
let errorLocation = buildError.broccoliPayload.error.location || {};
41+
let {
42+
file: fileName,
43+
line,
44+
column
45+
} = errorLocation;
46+
47+
if (fileName) {
48+
let normalisedFileName = getNormalisedFileName(fileName, line, column);
49+
50+
return launchEditor(normalisedFileName, () => {
51+
if (!process.env.EDITOR && !process.env.VISUAL) {
52+
console.log(
53+
'To set up the editor integration, set the env variables EDITOR or VISUAL ' +
54+
'to an editor of your choice and restart the server.'
55+
);
56+
}
57+
});
58+
}
59+
}
60+
3761
errorHandler(response, {
3862
'buildError': buildError,
3963
'liveReloadPath': options.liveReloadPath

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"homepage": "https://github.com/ember-cli/broccoli-middleware",
2121
"dependencies": {
2222
"handlebars": "^4.0.4",
23+
"launch-editor": "^2.2.1",
2324
"mime-types": "^2.1.18"
2425
},
2526
"devDependencies": {

test/filename-normaliser-test.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
'use strict';
2+
3+
const expect = require('chai').expect;
4+
const normaliseFileName = require('./../lib/utils/filename-normaliser').normaliseFileName;
5+
6+
describe('file name normaliser', function() {
7+
describe('handles module unification layout', function() {
8+
it('components are normalised correctly', function() {
9+
const fileName = 'src/ui/components/my-component/template.hbs';
10+
const normalisedFileName = normaliseFileName(fileName);
11+
12+
expect(normalisedFileName).to.equal(fileName);
13+
});
14+
});
15+
16+
describe('handles pod layout', function() {
17+
it('components are normalised correctly', function() {
18+
const fileName = 'broccoli-middleware/components/awesome-component/template.hbs';
19+
const expectedFileName = 'app/components/awesome-component/template.hbs';
20+
const normalisedFileName = normaliseFileName(fileName);
21+
22+
expect(normalisedFileName).to.equal(expectedFileName);
23+
});
24+
25+
it('templates are normalised correctly', function() {
26+
const fileName = 'broccoli-middleware/awesome-route/template.hbs';
27+
const expectedFileName = 'app/awesome-route/template.hbs';
28+
const normalisedFileName = normaliseFileName(fileName);
29+
30+
expect(normalisedFileName).to.equal(expectedFileName);
31+
});
32+
33+
describe('in-repo engines are normalised correctly', function() {
34+
it('components are normalised correctly', function() {
35+
const fileName = 'awesome-engine/components/awesome-component/template.hbs';
36+
const expectedFileName = 'lib/awesome-engine/addon/components/awesome-component/template.hbs';
37+
const normalisedFileName = normaliseFileName(fileName);
38+
39+
expect(normalisedFileName).to.equal(expectedFileName);
40+
});
41+
42+
it('templates are normalised correctly', function() {
43+
const fileName = 'awesome-engine/awesome-route/template.hbs';
44+
const expectedFileName = 'lib/awesome-engine/addon/awesome-route/template.hbs';
45+
const normalisedFileName = normaliseFileName(fileName);
46+
47+
expect(normalisedFileName).to.equal(expectedFileName);
48+
});
49+
});
50+
});
51+
52+
describe('handles classic layout', function() {
53+
it('components are normalised correctly', function() {
54+
const fileName = 'broccoli-middleware/templates/components/awesome-component.hbs';
55+
const expectedFileName = 'app/templates/components/awesome-component.hbs';
56+
const normalisedFileName = normaliseFileName(fileName);
57+
58+
expect(normalisedFileName).to.equal(expectedFileName);
59+
});
60+
61+
it('templates are normalised correctly', function() {
62+
const fileName = 'broccoli-middleware/templates/application.hbs';
63+
const expectedFileName = 'app/templates/application.hbs';
64+
const normalisedFileName = normaliseFileName(fileName);
65+
66+
expect(normalisedFileName).to.equal(expectedFileName);
67+
});
68+
69+
describe('in-repo engines are normalised correctly', function() {
70+
it('components are normalised correctly', function() {
71+
const fileName = 'awesome-engine/templates/components/awesome-component.hbs';
72+
const expectedFileName = 'lib/awesome-engine/addon/templates/components/awesome-component.hbs';
73+
const normalisedFileName = normaliseFileName(fileName);
74+
75+
expect(normalisedFileName).to.equal(expectedFileName);
76+
});
77+
78+
it('templates are normalised correctly', function() {
79+
const fileName = 'awesome-engine/templates/awesome-route.hbs';
80+
const expectedFileName = 'lib/awesome-engine/addon/templates/awesome-route.hbs';
81+
const normalisedFileName = normaliseFileName(fileName);
82+
83+
expect(normalisedFileName).to.equal(expectedFileName);
84+
});
85+
});
86+
});
87+
});

0 commit comments

Comments
 (0)