Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/core/__tests__/language-server/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ describe('Language Server: Diagnostics (ts plugin)', () => {
"code": 2554,
"end": {
"line": 15,
"offset": 17,
"offset": 14,
},
"relatedInformation": [
{
Expand All @@ -406,7 +406,7 @@ describe('Language Server: Diagnostics (ts plugin)', () => {
],
"start": {
"line": 15,
"offset": 5,
"offset": 6,
},
"text": "Expected 1 arguments, but got 0.",
},
Expand Down
12 changes: 12 additions & 0 deletions packages/core/__tests__/transform/template-to-typescript.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,9 @@ describe('Transform: rewriteTemplate', () => {
expect(templateBody(template, { globals: [] })).toMatchInlineSnapshot(`
"{
const __glintY__ = __glintDSL__.emitElement("div");
__glintDSL__.applyAttributes(__glintY__.element, {

});
__glintDSL__.applyModifier(__glintDSL__.resolve(modifier)(__glintY__.element, { foo: "bar" , ...__glintDSL__.NamedArgsMarker }));
}"
`);
Expand All @@ -832,6 +835,9 @@ describe('Transform: rewriteTemplate', () => {
expect(templateBody(template, { globals: [] })).toMatchInlineSnapshot(`
"{
const __glintY__ = __glintDSL__.emitComponent(__glintDSL__.resolve(MyComponent)());
__glintDSL__.applyAttributes(__glintY__.element, {

});
__glintDSL__.applyModifier(__glintDSL__.resolve(modifier)(__glintY__.element, { foo: "bar" , ...__glintDSL__.NamedArgsMarker }));
}"
`);
Expand Down Expand Up @@ -973,6 +979,9 @@ describe('Transform: rewriteTemplate', () => {
"{
const __glintY__ = __glintDSL__.emitElement("div");
__glintDSL__.applySplattributes(__glintRef__.element, __glintY__.element);
__glintDSL__.applyAttributes(__glintY__.element, {

});
}"
`);
});
Expand Down Expand Up @@ -1017,6 +1026,9 @@ describe('Transform: rewriteTemplate', () => {
"{
const __glintY__ = __glintDSL__.emitComponent(__glintDSL__.resolve(Foo)());
__glintDSL__.applySplattributes(__glintRef__.element, __glintY__.element);
__glintDSL__.applyAttributes(__glintY__.element, {

});
}"
`);
});
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"test:tsc": "echo 'no standalone typecheck within this project'",
"test:watch": "vitest watch",
"build": "tsc --build",
"dev": "tsc --watch",
"prepack": "pnpm build"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/transform/diagnostics/augmentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ function checkImplicitAnyError(
// This error may appear either on `<Foo />` or `{{foo}}`/`(foo)`
let globalName =
sourceNode.type === 'ElementNode'
? sourceNode.tag.split('.')[0]
? sourceNode.path.head.original
: sourceNode.type === 'PathExpression' && sourceNode.head.type === 'VarHead'
? sourceNode.head.name
: null;
Expand Down
26 changes: 23 additions & 3 deletions packages/core/src/transform/template/map-template-contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type Mapper = {
* Given a @glimmer/syntax AST node, returns the corresponding start
* and end offsets of that node in the original source.
*/
rangeForNode: (node: AST.Node) => Range;
rangeForNode: (node: AST.Node, span?: AST.Node['loc']) => Range;

/**
* Captures the existence of a directive specified by the given source
Expand Down Expand Up @@ -81,6 +81,12 @@ export type Mapper = {
* corresponding to the given AST node in the original source.
*/
forNode(node: AST.Node, callback: () => void, codeFeaturesForNode?: CodeInformation): void;
forNodeWithSpan(
node: AST.Node,
span: AST.Node['loc'],
callback: () => void,
codeFeaturesForNode?: CodeInformation,
): void;

/**
* This needs to be called after any node that "consumes" a `glint-expect-error` directive.
Expand Down Expand Up @@ -311,6 +317,15 @@ export function mapTemplateContents(
captureMapping(mapper.rangeForNode(node), node, false, callback, codeFeaturesForNode);
},

forNodeWithSpan(
node: AST.Node,
span: AST.Node['loc'],
callback: () => void,
codeFeaturesForNode?: CodeInformation,
) {
captureMapping(mapper.rangeForNode(node, span), node, false, callback, codeFeaturesForNode);
},

error(message: string, location: Range) {
errors.push({ message, location });
},
Expand Down Expand Up @@ -460,9 +475,14 @@ function calculateLineOffsets(template: string, contentOffset: number): Array<nu
return offsets;
}

function buildRangeForNode(offsets: Array<number>): (node: AST.Node) => Range {
return (node) => {
function buildRangeForNode(
offsets: Array<number>,
): (node: AST.Node, span?: AST.Node['loc']) => Range {
return (node, span) => {
let { loc } = node;
if (span) {
loc = span;
}
let start = offsets[loc.start.line] + loc.start.column;
let end = offsets[loc.end.line] + loc.end.column;

Expand Down
65 changes: 37 additions & 28 deletions packages/core/src/transform/template/template-to-typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ export function templateToTypescript(
mapper.text('const __glintY__ = __glintDSL__.emitComponent(');

// Error boundary: "Expected 1 arguments, but got 0." e.g. when invoking `<ComponentThatHasArgs />`
mapper.forNode(node, () => {
mapper.forNode(node.path, () => {
mapper.text('__glintDSL__.resolve(');
emitPathContents(path, start, kind);
mapper.text(')');
Expand All @@ -707,7 +707,7 @@ export function templateToTypescript(
let dataAttrs = node.attributes.filter(({ name }) => name.startsWith('@'));
if (dataAttrs.length) {
// Error boundary: "Expected 0 arguments, but got 1." e.g. when invoking `<ComponentThatHasNoArgs @foo={{bar}} />`
mapper.forNode(node, () => {
mapper.forNodeWithSpan(node, node.openTag, () => {
mapper.text('{ ');

for (let attr of dataAttrs) {
Expand Down Expand Up @@ -883,7 +883,9 @@ export function templateToTypescript(
mapper.indent();

mapper.text('const __glintY__ = __glintDSL__.emitElement(');
mapper.text(JSON.stringify(node.tag));
mapper.forNode(node.path, () => {
mapper.text(JSON.stringify(node.tag));
});
mapper.text(');');
mapper.newline();

Expand Down Expand Up @@ -930,39 +932,46 @@ export function templateToTypescript(
(attr) => !attr.name.startsWith('@') && attr.name !== SPLATTRIBUTES,
);

if (!attributes.length) return;

mapper.text('__glintDSL__.applyAttributes(__glintY__.element, {');
mapper.newline();
mapper.indent();

let start = template.indexOf(node.tag, rangeForNode(node).start) + node.tag.length;
mapper.forNodeWithSpan(node, node.openTag, () => {
mapper.newline();
mapper.indent();

for (let attr of attributes) {
mapper.forNode(attr, () => {
start = template.indexOf(attr.name, start + 1);
let start = template.indexOf(node.tag, rangeForNode(node).start) + node.tag.length;

emitHashKey(attr.name, start);
mapper.text(': ');
for (let attr of attributes) {
mapper.forNode(attr, () => {
start = template.indexOf(attr.name, start + 1);

if (attr.value.type === 'MustacheStatement') {
emitMustacheStatement(attr.value, 'attr');
} else if (attr.value.type === 'ConcatStatement') {
emitConcatStatement(attr.value);
} else {
mapper.text(JSON.stringify(attr.value.chars));
}
emitHashKey(attr.name, start);
mapper.text(': ');

mapper.text(',');
mapper.newline();
});
if (attr.value.type === 'MustacheStatement') {
emitMustacheStatement(attr.value, 'attr');
} else if (attr.value.type === 'ConcatStatement') {
emitConcatStatement(attr.value);
} else {
mapper.text(JSON.stringify(attr.value.chars));
}

mapper.terminateDirectiveAreaOfEffect('emitPlainAttributes');
}
mapper.text(',');
mapper.newline();
});

mapper.dedent();
mapper.text('});');
mapper.newline();
mapper.terminateDirectiveAreaOfEffect('emitPlainAttributes');
}

// in case there are no attributes, this would allow completions to trigger
if (attributes.length === 0) {
mapper.text(' ');
mapper.newline();
}

mapper.dedent();
mapper.text('});');
mapper.newline();
});
}

function emitSplattributes(node: AST.ElementNode): void {
Expand Down
Loading