Skip to content

Commit e67b4ac

Browse files
authored
Merge pull request #56 from typed-ember/default-export-error-reporting
2 parents 2be6f09 + 896b72f commit e67b4ac

File tree

4 files changed

+87
-9
lines changed

4 files changed

+87
-9
lines changed

packages/transform/__tests__/rewrite.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,68 @@ describe('rewriteModule', () => {
265265
`);
266266
});
267267

268+
test('with no default value export', () => {
269+
let script = {
270+
filename: 'test.ts',
271+
contents: stripIndent`
272+
import Component from '@glimmer/component';
273+
export class MyComponent extends Component {}
274+
`,
275+
};
276+
277+
let template = {
278+
filename: 'test.hbs',
279+
contents: stripIndent``,
280+
};
281+
282+
let transformedModule = rewriteModule({ script, template }, emberLooseEnvironment);
283+
284+
expect(transformedModule?.errors).toEqual([
285+
{
286+
message:
287+
'Modules with an associated template must have a default export that is a class declaration or expression',
288+
source: script,
289+
location: {
290+
start: 0,
291+
end: script.contents.length,
292+
},
293+
},
294+
]);
295+
296+
expect(transformedModule?.getOriginalRange(0, script.contents.length)).toEqual({
297+
source: script,
298+
start: 0,
299+
end: script.contents.length,
300+
});
301+
});
302+
303+
test('with an unresolvable default export', () => {
304+
let script = {
305+
filename: 'test.ts',
306+
contents: stripIndent`
307+
export default Foo;
308+
`,
309+
};
310+
311+
let template = {
312+
filename: 'test.hbs',
313+
contents: stripIndent``,
314+
};
315+
316+
let transformedModule = rewriteModule({ script, template }, emberLooseEnvironment);
317+
318+
expect(transformedModule?.errors).toEqual([
319+
{
320+
message: 'Unable to resolve a class body to associate a template declaration to',
321+
source: script,
322+
location: {
323+
start: script.contents.indexOf('Foo'),
324+
end: script.contents.indexOf(';'),
325+
},
326+
},
327+
]);
328+
});
329+
268330
test('with a class with default export in module augmentation', () => {
269331
let script = {
270332
filename: 'test.ts',

packages/transform/src/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ function calculateCorrelatedSpans(
137137
): CorrelatedSpansResult {
138138
let errors: Array<TransformError> = [];
139139
let partialSpans: Array<PartialCorrelatedSpan> = [];
140+
let defaultExportSeen = false;
140141

141142
traverse(ast, {
142143
TaggedTemplateExpression(path) {
@@ -152,15 +153,25 @@ function calculateCorrelatedSpans(
152153
},
153154

154155
ExportDefaultDeclaration(path) {
155-
if (template) {
156-
let result = calculateCompanionTemplateSpans(path, script, template, environment);
156+
let declaration = path.get('declaration');
157+
if (template && (declaration.isClass() || declaration.isExpression())) {
158+
let result = calculateCompanionTemplateSpans(declaration, script, template, environment);
157159

160+
defaultExportSeen = true;
158161
errors.push(...result.errors);
159162
partialSpans.push(...result.partialSpans);
160163
}
161164
},
162165
});
163166

167+
if (template && !defaultExportSeen) {
168+
errors.push({
169+
message: `Modules with an associated template must have a default export that is a class declaration or expression`,
170+
source: script,
171+
location: { start: 0, end: script.contents.length },
172+
});
173+
}
174+
164175
return { errors, partialSpans };
165176
}
166177

packages/transform/src/inlining/companion-file.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { assert } from '../util';
99
const STANDALONE_TEMPLATE_FIELD = `'~template'`;
1010

1111
export function calculateCompanionTemplateSpans(
12-
path: NodePath<t.ExportDefaultDeclaration>,
12+
path: NodePath<t.Class> | NodePath<t.Expression>,
1313
script: SourceFile,
1414
template: SourceFile,
1515
environment: GlintEnvironment
@@ -30,9 +30,12 @@ export function calculateCompanionTemplateSpans(
3030
let targetPath = findCompanionTemplateTarget(path);
3131
if (!targetPath) {
3232
errors.push({
33+
message: `Unable to resolve a class body to associate a template declaration to`,
3334
source: script,
34-
location: { start: 0, end: script.contents.length },
35-
message: `Modules with an associated template must have a default export`,
35+
location: {
36+
start: path.node.start ?? 0,
37+
end: path.node.end ?? script.contents.length,
38+
},
3639
});
3740

3841
return { errors, partialSpans };
@@ -124,11 +127,10 @@ export function calculateCompanionTemplateSpans(
124127
type CompanionTemplateTarget = NodePath<t.Class> | NodePath<t.Expression> | null;
125128

126129
function findCompanionTemplateTarget(
127-
path: NodePath<t.ExportDefaultDeclaration>
130+
declaration: NodePath<t.Class> | NodePath<t.Expression>
128131
): CompanionTemplateTarget {
129-
let declaration = path.get('declaration');
130132
let value = declaration.isIdentifier()
131-
? path.scope.getBinding(declaration.node.name)?.path
133+
? declaration.scope.getBinding(declaration.node.name)?.path
132134
: declaration;
133135

134136
if (value?.isClass() || value?.isExpression()) {

packages/transform/src/transformed-module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ export default class TransformedModule {
8181
let startInfo = this.determineOriginalOffsetAndSpan(transformedStart);
8282
let endInfo = this.determineOriginalOffsetAndSpan(transformedEnd);
8383

84-
assert(startInfo.correlatedSpan.originalFile === endInfo.correlatedSpan.originalFile);
84+
assert(
85+
startInfo.correlatedSpan.originalFile === endInfo.correlatedSpan.originalFile,
86+
'Attempted to transform a range across two different files'
87+
);
8588

8689
let source = startInfo.correlatedSpan.originalFile;
8790
let start = startInfo.originalOffset;

0 commit comments

Comments
 (0)