diff --git a/src/parse.js b/src/parse.js
index 3125858..a41491e 100644
--- a/src/parse.js
+++ b/src/parse.js
@@ -88,6 +88,11 @@ export function toTree(source, options = {}) {
}
let parseResults = preprocessor.parse(source);
+ // content-tag reports a class's own template before a template that sits
+ // earlier in its heritage clause (`class A extends mixin() {
+ // }`); `toPlaceholderJS` walks the source forward, so it needs
+ // them in source order.
+ parseResults.sort((a, b) => a.range.startUtf16Codepoint - b.range.startUtf16Codepoint);
let js = toPlaceholderJS(source, parseResults);
const useCustomParser = !!options.parser;
diff --git a/tests/parse.test.js b/tests/parse.test.js
index 38d76a8..bd31f4b 100644
--- a/tests/parse.test.js
+++ b/tests/parse.test.js
@@ -137,6 +137,30 @@ describe("parse", () => {
expect(mustache).toBeTruthy();
});
+ it("handles a template in a heritage clause before the class body template", () => {
+ // content-tag reports these two templates in the opposite order from
+ // their position in the source.
+ const source = [
+ "const mixin = (base, t) => base;",
+ "export class Both extends mixin(Object, heritage) {",
+ " own",
+ "}",
+ "const after = 1;",
+ ].join("\n");
+ const ast = parse(source);
+
+ expect(ast.program.body.map((node) => node.type)).toEqual([
+ "VariableDeclaration",
+ "ExportNamedDeclaration",
+ "VariableDeclaration",
+ ]);
+ const templates = findAllNodes(ast, "GlimmerTemplate");
+ expect(templates.map((t) => source.slice(t.start, t.end))).toEqual([
+ "heritage",
+ "own",
+ ]);
+ });
+
it("handles multiple classes with templates", () => {
const source = `class A extends Component {
A