Skip to content

Commit

Permalink
Add annotateSourceFile option (#375)
Browse files Browse the repository at this point in the history
Co-authored-by: Princesseuh <[email protected]>
  • Loading branch information
natemoo-re and Princesseuh authored Nov 8, 2023
1 parent d6a4ba1 commit 0c24ea1
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .changeset/stale-steaks-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
'@astrojs/compiler': minor
---

Add a new `annotateSourceFile` option. This option makes it so the compiler will annotate every element with its source file location. This is notably useful for dev tools to be able to provide features like a "Open in editor" button. This option is disabled by default.

```html
<div>
<span>hello world</span>
</div>
```

Results in:

```html
<div data-astro-source-file="/Users/erika/Projects/..." data-astro-source-loc="1:1">
<span data-astro-source-file="/Users/erika/Projects/..." data-astro-source-loc="2:2">hello world</span>
</div>
```

In Astro, this option is enabled only in development mode.
7 changes: 7 additions & 0 deletions cmd/astro-wasm/astro-wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,17 @@ func makeTransformOptions(options js.Value) transform.TransformOptions {
if jsBool(options.Get("resultScopedSlot")) {
scopedSlot = true
}

transitionsAnimationURL := jsString(options.Get("transitionsAnimationURL"))
if transitionsAnimationURL == "" {
transitionsAnimationURL = "astro/components/viewtransitions.css"
}

annotateSourceFile := false
if jsBool(options.Get("annotateSourceFile")) {
annotateSourceFile = true
}

var resolvePath any = options.Get("resolvePath")
var resolvePathFn func(string) string
if resolvePath.(js.Value).Type() == js.TypeFunction {
Expand Down Expand Up @@ -132,6 +138,7 @@ func makeTransformOptions(options js.Value) transform.TransformOptions {
ResultScopedSlot: scopedSlot,
ScopedStyleStrategy: scopedStyleStrategy,
TransitionsAnimationURL: transitionsAnimationURL,
AnnotateSourceFile: annotateSourceFile,
}
}

Expand Down
20 changes: 20 additions & 0 deletions internal/printer/print-to-js.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"sort"
"strings"
"unicode"

. "github.com/withastro/compiler/internal"
"github.com/withastro/compiler/internal/handler"
Expand Down Expand Up @@ -448,6 +449,25 @@ func render1(p *printer, n *Node, opts RenderOptions) {
// Note: if we encounter "slot" NOT inside a component, that's fine
// These should be preserved in the output
p.printAttribute(a, n)
} else if a.Key == "data-astro-source-file" {
p.printAttribute(a, n)
var l []int
if n.FirstChild != nil && len(n.FirstChild.Loc) > 0 {
start := n.FirstChild.Loc[0].Start
if n.FirstChild.Type == TextNode {
start += len(n.Data) - len(strings.TrimLeftFunc(n.Data, unicode.IsSpace))
}
l = p.builder.GetLineAndColumnForLocation(loc.Loc{Start: start})
} else if len(n.Loc) > 0 {
l = p.builder.GetLineAndColumnForLocation(n.Loc[0])
}
if len(l) > 0 {
p.printAttribute(Attribute{
Key: "data-astro-source-loc",
Type: QuotedAttribute,
Val: fmt.Sprintf("%d:%d", l[0], l[1]),
}, n)
}
p.addSourceMapping(n.Loc[0])
} else {
p.printAttribute(a, n)
Expand Down
20 changes: 20 additions & 0 deletions internal/transform/scope-html.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

astro "github.com/withastro/compiler/internal"
"golang.org/x/net/html/atom"
)

func ScopeElement(n *astro.Node, opts TransformOptions) {
Expand All @@ -27,6 +28,14 @@ func AddDefineVars(n *astro.Node, values []string) bool {
return false
}

func AnnotateElement(n *astro.Node, opts TransformOptions) {
if n.Type == astro.ElementNode && !n.Component && !n.Fragment {
if _, noScope := NeverScopedElements[n.Data]; !noScope {
annotateElement(n, opts)
}
}
}

var NeverScopedElements map[string]bool = map[string]bool{
"Fragment": true,
"base": true,
Expand All @@ -48,6 +57,17 @@ var NeverScopedSelectors map[string]bool = map[string]bool{
":root": true,
}

func annotateElement(n *astro.Node, opts TransformOptions) {
if n.DataAtom == atom.Html {
return
}
n.Attr = append(n.Attr, astro.Attribute{
Key: "data-astro-source-file",
Type: astro.QuotedAttribute,
Val: opts.Filename,
})
}

func injectDefineVars(n *astro.Node, values []string) {
definedVars := "$$definedVars"
for i, attr := range n.Attr {
Expand Down
4 changes: 4 additions & 0 deletions internal/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type TransformOptions struct {
TransitionsAnimationURL string
ResolvePath func(string) string
PreprocessStyle interface{}
AnnotateSourceFile bool
}

func Transform(doc *astro.Node, opts TransformOptions, h *handler.Handler) *astro.Node {
Expand Down Expand Up @@ -59,6 +60,9 @@ func Transform(doc *astro.Node, opts TransformOptions, h *handler.Handler) *astr
if n.DataAtom == a.Head && !IsImplicitNode(n) {
doc.ContainsHead = true
}
if opts.AnnotateSourceFile {
AnnotateElement(n, opts)
}
})
if len(definedVars) > 0 && !didAddDefinedVars {
for _, style := range doc.Styles {
Expand Down
45 changes: 45 additions & 0 deletions internal/transform/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,48 @@ func TestCompactTransform(t *testing.T) {
})
}
}

func TestAnnotation(t *testing.T) {
tests := []struct {
name string
source string
want string
}{
{
name: "basic",
source: `<div>Hello world!</div>`,
want: `<div data-astro-source-file="/src/pages/index.astro">Hello world!</div>`,
},
{
name: "no components",
source: `<Component>Hello world!</Component>`,
want: `<Component>Hello world!</Component>`,
},
{
name: "injects root",
source: `<html></html>`,
want: `<html></html>`,
},
}
var b strings.Builder
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b.Reset()
doc, err := astro.Parse(strings.NewReader(tt.source))
if err != nil {
t.Error(err)
}
h := handler.NewHandler(tt.source, "/src/pages/index.astro")
Transform(doc, TransformOptions{
AnnotateSourceFile: true,
Filename: "/src/pages/index.astro",
NormalizedFilename: "/src/pages/index.astro",
}, h)
astro.PrintToSource(&b, doc)
got := strings.TrimSpace(b.String())
if tt.want != got {
t.Errorf("\nFAIL: %s\n want: %s\n got: %s", tt.name, tt.want, got)
}
})
}
}
1 change: 1 addition & 0 deletions packages/compiler/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface TransformOptions {
transitionsAnimationURL?: string;
resolvePath?: (specifier: string) => Promise<string>;
preprocessStyle?: (content: string, attrs: Record<string, string>) => null | Promise<PreprocessorResult | PreprocessorError>;
annotateSourceFile?: boolean;
}

export type ConvertToTSXOptions = Pick<TransformOptions, 'filename' | 'normalizedFilename'>;
Expand Down

0 comments on commit 0c24ea1

Please sign in to comment.