From f9ca63cda20a5d960b999b804d364d9e1214d984 Mon Sep 17 00:00:00 2001 From: Princesseuh <3019731+Princesseuh@users.noreply.github.com> Date: Mon, 5 Aug 2024 02:42:52 +0200 Subject: [PATCH 1/4] fix(tsx): Extract positions based on utf-16 encoding --- internal/printer/print-to-tsx.go | 40 +++++++++------ internal/printer/printer.go | 19 -------- packages/compiler/src/shared/types.ts | 4 ++ packages/compiler/test/tsx/meta.ts | 70 +++++++++++++++++++++++---- 4 files changed, 90 insertions(+), 43 deletions(-) diff --git a/internal/printer/print-to-tsx.go b/internal/printer/print-to-tsx.go index 95636b88..d622bde0 100644 --- a/internal/printer/print-to-tsx.go +++ b/internal/printer/print-to-tsx.go @@ -13,6 +13,7 @@ import ( "github.com/withastro/compiler/internal/loc" "github.com/withastro/compiler/internal/sourcemap" "github.com/withastro/compiler/internal/transform" + esbuild "github.com/withastro/compiler/lib/esbuild/helpers" "golang.org/x/net/html/atom" ) @@ -41,6 +42,11 @@ func PrintToTSX(sourcetext string, n *Node, opts TSXOptions, transformOpts trans } } +func getUTF16Length(s string) int { + // Go has a built-in module for utf16, but esbuild's is faster and slightly more friendly + return len(esbuild.StringToUTF16(s)) +} + type TSXRanges struct { Frontmatter loc.TSXRange `js:"frontmatter"` Body loc.TSXRange `js:"body"` @@ -318,7 +324,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { props := js_scanner.GetPropsType(source) hasGetStaticPaths := js_scanner.HasGetStaticPaths(source) hasChildren := false - startLoc := len(p.output) + startLoc := getUTF16Length(string(p.output)) for c := n.FirstChild; c != nil; c = c.NextSibling { // This checks for the first node that comes *after* the frontmatter // to ensure that the statement is properly closed with a `;`. @@ -338,7 +344,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.print("\n") // Update the start location of the body to the start of the first child - startLoc = len(p.output) + startLoc = getUTF16Length(string(p.output)) hasChildren = true } @@ -346,7 +352,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.addNilSourceMapping() p.print("\n") - startLoc = len(p.output) + startLoc = getUTF16Length(string(p.output)) hasChildren = true } @@ -358,7 +364,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.addNilSourceMapping() p.setTSXBodyRange(loc.TSXRange{ Start: startLoc, - End: len(p.output), + End: getUTF16Length(string(p.output)), }) // Only close the body with `` if we printed a body @@ -401,7 +407,7 @@ declare const Astro: Readonly 0 { @@ -420,7 +426,7 @@ declare const Astro: Readonly") - startTagEnd := endLoc - p.bytesToSkip + contentToStartTagEnd := p.sourcetext[:endLoc] // Render any child nodes for c := n.FirstChild; c != nil; c = c.NextSibling { @@ -760,11 +765,16 @@ declare const Astro: Readonly len(p.sourcetext) { // Sometimes, when tags are not closed properly and stuff, endLoc can be greater than the length of the source text, wonky stuff + maxLength = len(p.sourcetext) + } + contentToContentEnd := p.sourcetext[:maxLength] if n.DataAtom == atom.Script { - p.addTSXScript(startTagEnd, endLoc-p.bytesToSkip, n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr)) + p.addTSXScript(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr)) } if n.DataAtom == atom.Style { - p.addTSXStyle(startTagEnd, endLoc-p.bytesToSkip, n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr)) + p.addTSXStyle(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr)) } } diff --git a/internal/printer/printer.go b/internal/printer/printer.go index 7cb4f30c..6e2af9f3 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -36,9 +36,6 @@ type printer struct { // Optional, used only for TSX output ranges TSXRanges - // Keep track of how many multi-byte characters we've printed so that they can be skipped whenever we need a character-based index - // This could be directly in the token / node information, however this would require a fairly large refactor - bytesToSkip int } var TEMPLATE_TAG = "$$render" @@ -119,9 +116,6 @@ func (p *printer) printTextWithSourcemap(text string, l loc.Loc) { continue } _, nextCharByteSize := utf8.DecodeRuneInString(text[pos:]) - if nextCharByteSize > 1 { - p.bytesToSkip += nextCharByteSize - 1 - } p.addSourceMapping(loc.Loc{Start: start}) p.print(string(c)) start += nextCharByteSize @@ -150,25 +144,12 @@ func (p *printer) printEscapedJSXTextWithSourcemap(text string, l loc.Loc) { } _, nextCharByteSize := utf8.DecodeRuneInString(text[pos:]) - if nextCharByteSize > 1 { - p.bytesToSkip += nextCharByteSize - 1 - } p.addSourceMapping(loc.Loc{Start: start}) p.print(string(c)) start += nextCharByteSize } } -// We normally collect multi-byte characters while printing, but this method can be used for skipped text -func (p *printer) collectMultiByteCharacters(text string) { - for pos := range text { - _, nextCharByteSize := utf8.DecodeRuneInString(text[pos:]) - if nextCharByteSize > 1 { - p.bytesToSkip += nextCharByteSize - 1 - } - } -} - func (p *printer) printInternalImports(importSpecifier string, opts *RenderOptions) { if p.hasInternalImports { return diff --git a/packages/compiler/src/shared/types.ts b/packages/compiler/src/shared/types.ts index 74a9d6f4..8ac85802 100644 --- a/packages/compiler/src/shared/types.ts +++ b/packages/compiler/src/shared/types.ts @@ -124,6 +124,10 @@ export interface SourceMap { version: number; } +/** + * Represents a location in a TSX file. + * Both the `start` and `end` properties are 0-based, and are based off utf-16 code units. (i.e. JavaScript's `String.prototype.length`) + */ export interface TSXLocation { start: number; end: number; diff --git a/packages/compiler/test/tsx/meta.ts b/packages/compiler/test/tsx/meta.ts index d2cc9c8b..d7136ac6 100644 --- a/packages/compiler/test/tsx/meta.ts +++ b/packages/compiler/test/tsx/meta.ts @@ -38,6 +38,24 @@ test('return ranges - no frontmatter', async () => { }); }); +test('return proper ranges with multibyte characters', async () => { + const input = '---\nšŸ¦„\n---\n\n
'; + const { metaRanges } = await convertToTSX(input, { sourcemap: 'external' }); + + assert.equal(metaRanges, { + frontmatter: { + start: 30, + end: 35, + }, + body: { + start: 49, + end: 61, + }, + scripts: null, + styles: null, + }); +}); + test('extract scripts', async () => { const input = `
`; @@ -164,7 +182,7 @@ test('extract styles', async () => { test('extract scripts and styles with multibyte characters', async () => { const scripts = ""; const styles = - ""; const input = `${scripts}${styles}`; const { metaRanges } = await convertToTSX(input, { sourcemap: 'external' }); @@ -175,7 +193,7 @@ test('extract scripts and styles with multibyte characters', async () => { { position: { start: 8, - end: 24, + end: 25, }, type: 'processed-module', content: "console.log('šŸ¦„')", @@ -183,8 +201,8 @@ test('extract scripts and styles with multibyte characters', async () => { }, { position: { - start: 41, - end: 60, + start: 42, + end: 61, }, type: 'processed-module', content: "console.log('Hey');", @@ -198,8 +216,8 @@ test('extract scripts and styles with multibyte characters', async () => { [ { position: { - start: 76, - end: 110, + start: 77, + end: 112, }, type: 'tag', content: "body { background: url('šŸ¦„.png'); }", @@ -207,11 +225,11 @@ test('extract scripts and styles with multibyte characters', async () => { }, { position: { - start: 125, - end: 186, + start: 127, + end: 159, }, type: 'tag', - content: "body { background: url('Hey');", + content: "body { background: url('Hey'); }", lang: 'css', }, ], @@ -219,4 +237,38 @@ test('extract scripts and styles with multibyte characters', async () => { ); }); +test('extract scripts with multibyte characters II', async () => { + // Emojis with various byte lengths (in order, 4, 3, 8, 28) and newlines, a complicated case, if you will + const input = `šŸ€„āœ‚šŸ‡øšŸ‡ŖšŸ‘©šŸ»ā€ā¤ļøā€šŸ‘©šŸ½šŸ€„āœ‚šŸ‡øšŸ‡ŖšŸ‘©šŸ»ā€ā¤ļøā€šŸ‘©šŸ½
`; + + const { metaRanges } = await convertToTSX(input, { sourcemap: 'external' }); + + assert.equal( + metaRanges.scripts, + [ + { + position: { + start: 27, + end: 65, + }, + type: 'processed-module', + content: '\n\tconsole.log("šŸ€„āœ‚šŸ‡øšŸ‡ŖšŸ‘©šŸ»ā€ā¤ļøā€šŸ‘©šŸ½");\n', + lang: '', + }, + { + position: { + start: 106, + end: 141, + }, + type: 'event-attribute', + content: "console.log('šŸ€„āœ‚šŸ‡øšŸ‡ŖšŸ‘©šŸ»ā€ā¤ļøā€šŸ‘©šŸ½')", + lang: '', + }, + ], + 'expected metaRanges.scripts to match snapshot' + ); +}); + test.run(); From 5462a40641eeedf551035d4e424054d3821a608f Mon Sep 17 00:00:00 2001 From: Princesseuh <3019731+Princesseuh@users.noreply.github.com> Date: Mon, 5 Aug 2024 03:18:02 +0200 Subject: [PATCH 2/4] perf(tsx): benchmark and perf fixes --- internal/printer/print-to-tsx.go | 8 +- internal/printer/print-to-tsx_test.go | 147 ++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 internal/printer/print-to-tsx_test.go diff --git a/internal/printer/print-to-tsx.go b/internal/printer/print-to-tsx.go index d622bde0..c61218ea 100644 --- a/internal/printer/print-to-tsx.go +++ b/internal/printer/print-to-tsx.go @@ -574,14 +574,12 @@ declare const Astro: Readonly len(p.sourcetext) { // Sometimes, when tags are not closed properly and stuff, endLoc can be greater than the length of the source text, wonky stuff + if endLoc > len(p.sourcetext) { // Sometimes, when tags are not closed properly, endLoc can be greater than the length of the source text, wonky stuff maxLength = len(p.sourcetext) } contentToContentEnd := p.sourcetext[:maxLength] diff --git a/internal/printer/print-to-tsx_test.go b/internal/printer/print-to-tsx_test.go new file mode 100644 index 00000000..4d719bed --- /dev/null +++ b/internal/printer/print-to-tsx_test.go @@ -0,0 +1,147 @@ +package printer + +import ( + "strings" + "testing" + + astro "github.com/withastro/compiler/internal" + handler "github.com/withastro/compiler/internal/handler" + "github.com/withastro/compiler/internal/transform" +) + +func BenchmarkPrintToTSX(b *testing.B) { + source := `--- +import MobileMenu from "$components/layout/MobileMenu.astro"; +import MobileMenuSide from "$components/layout/MobileMenuSide.astro"; +import Header from "$components/layout/Header.astro"; +import Socials from "$components/layout/Socials.astro"; +import { getBaseSiteURL } from "$utils"; +import { Head } from "astro-capo"; +import "src/assets/style/prin.css"; +import type { MenuItem } from "../data/sidebarMenu"; +import Spritesheet from "$components/Spritesheet.astro"; +import GoBackUp from "$components/layout/GoBackUp.astro"; + +interface Props { + title?: string; + description?: string | undefined; + navItems?: MenuItem[]; + preloadCatalogue?: boolean; +} + +const { title, description, navItems, preloadCatalogue } = Astro.props; +const canonicalURL = new URL(Astro.url.pathname, Astro.site); +--- + + + + + + + + Erika + + + + + + {preloadCatalogue && } + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + + + + + +
+ + + +` + for i := 0; i < b.N; i++ { + h := handler.NewHandler(source, "AstroBenchmark") + var doc *astro.Node + doc, err := astro.ParseWithOptions(strings.NewReader(source), astro.ParseOptionWithHandler(h), astro.ParseOptionEnableLiteral(true)) + if err != nil { + h.AppendError(err) + } + + PrintToTSX(source, doc, TSXOptions{ + IncludeScripts: false, + IncludeStyles: false, + }, transform.TransformOptions{ + Filename: "AstroBenchmark", + }, h) + } +} From f7adf78bdf6718edbdde96c3b627386fec9dfa0d Mon Sep 17 00:00:00 2001 From: Princesseuh <3019731+Princesseuh@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:33:14 +0200 Subject: [PATCH 3/4] feat: re-use line offsets from sourcemapping logic --- internal/printer/print-to-tsx.go | 51 ++++++----- internal/printer/print-to-tsx_test.go | 121 ++------------------------ internal/sourcemap/sourcemap.go | 25 ++++++ 3 files changed, 62 insertions(+), 135 deletions(-) diff --git a/internal/printer/print-to-tsx.go b/internal/printer/print-to-tsx.go index c61218ea..2187317c 100644 --- a/internal/printer/print-to-tsx.go +++ b/internal/printer/print-to-tsx.go @@ -13,7 +13,6 @@ import ( "github.com/withastro/compiler/internal/loc" "github.com/withastro/compiler/internal/sourcemap" "github.com/withastro/compiler/internal/transform" - esbuild "github.com/withastro/compiler/lib/esbuild/helpers" "golang.org/x/net/html/atom" ) @@ -38,13 +37,26 @@ func PrintToTSX(sourcetext string, n *Node, opts TSXOptions, transformOpts trans return PrintResult{ Output: p.output, SourceMapChunk: p.builder.GenerateChunk(p.output), - TSXRanges: p.ranges, + TSXRanges: finalizeRanges(string(p.output), p.ranges), } } -func getUTF16Length(s string) int { - // Go has a built-in module for utf16, but esbuild's is faster and slightly more friendly - return len(esbuild.StringToUTF16(s)) +func finalizeRanges(content string, ranges TSXRanges) TSXRanges { + chunkBuilder := sourcemap.MakeChunkBuilder(nil, sourcemap.GenerateLineOffsetTables(content, len(strings.Split(content, "\n")))) + + return TSXRanges{ + Frontmatter: loc.TSXRange{ + Start: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Frontmatter.Start}), + End: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Frontmatter.End}), + }, + Body: loc.TSXRange{ + Start: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Body.Start}), + End: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Body.End}), + }, + // Scripts and styles are already using the proper positions + Scripts: ranges.Scripts, + Styles: ranges.Styles, + } } type TSXRanges struct { @@ -324,7 +336,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { props := js_scanner.GetPropsType(source) hasGetStaticPaths := js_scanner.HasGetStaticPaths(source) hasChildren := false - startLoc := getUTF16Length(string(p.output)) + startLen := len(p.output) for c := n.FirstChild; c != nil; c = c.NextSibling { // This checks for the first node that comes *after* the frontmatter // to ensure that the statement is properly closed with a `;`. @@ -344,7 +356,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.print("\n") // Update the start location of the body to the start of the first child - startLoc = getUTF16Length(string(p.output)) + startLen = len(p.output) hasChildren = true } @@ -352,7 +364,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.addNilSourceMapping() p.print("\n") - startLoc = getUTF16Length(string(p.output)) + startLen = len(p.output) hasChildren = true } @@ -363,8 +375,8 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) { p.addNilSourceMapping() p.setTSXBodyRange(loc.TSXRange{ - Start: startLoc, - End: getUTF16Length(string(p.output)), + Start: startLen, + End: len(p.output), }) // Only close the body with `` if we printed a body @@ -407,7 +419,7 @@ declare const Astro: Readonly 0 { @@ -426,7 +438,7 @@ declare const Astro: Readonly") - contentToStartTagEnd := p.sourcetext[:endLoc] + startTagEndLoc := loc.Loc{Start: endLoc} // Render any child nodes for c := n.FirstChild; c != nil; c = c.NextSibling { @@ -763,16 +775,15 @@ declare const Astro: Readonly len(p.sourcetext) { // Sometimes, when tags are not closed properly, endLoc can be greater than the length of the source text, wonky stuff - maxLength = len(p.sourcetext) + tagContentEndLoc.Start = len(p.sourcetext) } - contentToContentEnd := p.sourcetext[:maxLength] if n.DataAtom == atom.Script { - p.addTSXScript(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr)) + p.addTSXScript(p.builder.OffsetAt(startTagEndLoc), p.builder.OffsetAt(tagContentEndLoc), n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr)) } if n.DataAtom == atom.Style { - p.addTSXStyle(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr)) + p.addTSXStyle(p.builder.OffsetAt(startTagEndLoc), p.builder.OffsetAt(tagContentEndLoc), n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr)) } } diff --git a/internal/printer/print-to-tsx_test.go b/internal/printer/print-to-tsx_test.go index 4d719bed..0eccbd26 100644 --- a/internal/printer/print-to-tsx_test.go +++ b/internal/printer/print-to-tsx_test.go @@ -9,126 +9,17 @@ import ( "github.com/withastro/compiler/internal/transform" ) +// One of the more performance-sensitive parts of the compiler is the handling of multibytes characters, this benchmark is an extreme case of that. func BenchmarkPrintToTSX(b *testing.B) { - source := `--- -import MobileMenu from "$components/layout/MobileMenu.astro"; -import MobileMenuSide from "$components/layout/MobileMenuSide.astro"; -import Header from "$components/layout/Header.astro"; -import Socials from "$components/layout/Socials.astro"; -import { getBaseSiteURL } from "$utils"; -import { Head } from "astro-capo"; -import "src/assets/style/prin.css"; -import type { MenuItem } from "../data/sidebarMenu"; -import Spritesheet from "$components/Spritesheet.astro"; -import GoBackUp from "$components/layout/GoBackUp.astro"; + source := `šŸŒ˜šŸ”…šŸ”˜šŸ®šŸ”­šŸ”šŸ’šŸ„šŸ‘‹ šŸ˜šŸ‘½šŸ’½šŸŒ‰šŸŒ’šŸ” šŸ“‡šŸØšŸ’暟Ž·šŸŽÆšŸ’…šŸ“±šŸŽ­šŸ‘žšŸŽ«šŸ’šŸ¢šŸ•” augue tincidunt šŸ‘ šŸ’‹šŸŒµšŸ’ŒšŸŒšŸ„šŸ•‚šŸ¹šŸ“£šŸŸ šŸžšŸ²šŸ‘·šŸ—»šŸ¢šŸ«šŸ‘£šŸ¹šŸ”·šŸŽ¢šŸ‘­šŸ—šŸ‘ƒ šŸ“šŸˆšŸ“šŸ’„ et, šŸ‘½šŸ‘½šŸ”™šŸ’šŸ”™šŸ€ šŸžšŸšŸŽµšŸ’•šŸ‚šŸ­šŸŽ¬šŸŽ… ac šŸƒšŸ‘³šŸ“‘šŸ¶šŸ‘šŸ”· šŸ”•šŸ‘„šŸ¾šŸ‘”šŸ¢šŸ’— šŸŒ“šŸ”™šŸŒ”šŸˆšŸ”’šŸ”„šŸŽ¹šŸŽ šŸŽ¾šŸšŸŒšŸ“ƒšŸ’žšŸ“”šŸ”•šŸ• vel šŸŒŸšŸšŸ’“šŸŽ¾šŸ”·šŸ“ŖšŸ’¼šŸ‘£šŸ“š šŸ‘ŸšŸ’»šŸ—¾šŸŽ‹šŸ’šŸ¬šŸ®šŸ’‘ šŸˆšŸŒøšŸ“šŸ„šŸ’¦ et vivamus šŸ‘šŸ«šŸ”‰šŸ”¹šŸ’½šŸ™ rhoncus eu šŸ“°šŸ’«šŸ’€šŸŒŗ šŸ”‹šŸ’¾šŸ”±šŸ”·šŸŸ convallis facilisi vitae mollis šŸ“ØšŸ”ššŸ’®šŸ”ƒšŸŽ€šŸ¶ šŸŒ šŸ“‘šŸŽ¹šŸŒ‘šŸ“«šŸ—½šŸŠšŸ’šŸ”¼šŸ•“ ac šŸŒ‚šŸŒ³šŸŒŗšŸŽ­šŸ§šŸ‘ šŸ”­šŸ”‰šŸ’‰šŸ—šŸ‘ šŸ¦ šŸ”„šŸ‘”šŸŽ­šŸ‡ šŸ¤šŸ‚šŸŒšŸ‘œšŸ”ŗ ornare šŸ”½šŸŒ°šŸŽƒšŸ’šŸ‘© šŸ¬šŸŒ»šŸ©šŸ‘ŗšŸŽ†šŸ“£ risus šŸŒ¼šŸ‘§šŸŒ’šŸ„šŸ’„šŸŒ†šŸ–šŸ‘šŸ“  šŸ•™šŸˆšŸ‘žšŸ¢šŸ‘…šŸŽ½šŸ«šŸ‘ƒšŸŒ¾šŸ˜šŸ•‘šŸŽ¼šŸ’†šŸŽ³ šŸ»šŸ“µšŸ”‚šŸ©šŸ•¦šŸ‘•šŸ¶ šŸ’ššŸ®šŸ“ŸšŸ“ˆšŸŒ„šŸ‘±šŸ”š sem šŸ”µšŸ’±šŸ’­šŸ’« libero bibendum šŸŒæšŸ®šŸŽ§šŸ“šŸ’‰ šŸµšŸ”·šŸ’šŸœ sed metus, aliquam šŸ·šŸ¬šŸ“‡šŸ‘”šŸŽ“šŸ”»šŸŠšŸ““šŸ‚šŸŽ½ šŸ€šŸ’”šŸŗšŸŒ¾ šŸ’£šŸ‡šŸ¼šŸŒ€šŸŸšŸ‚šŸ° sed luctus šŸ‘¾šŸ šŸ‘»šŸ’¬šŸ“‹šŸˆšŸ‘€šŸŒ•šŸ’„šŸ¹ consectetur commodo at šŸ““šŸ£šŸ”®šŸšŸ”ŗšŸšŸ—»šŸƒšŸ šŸ”¬ šŸšŸŽ¬šŸ”šŸŒ™ šŸŽæšŸŽŠšŸ³šŸ’“šŸ‘¹šŸ šŸ‘¦šŸ©šŸ‘¶šŸ’» šŸ”‰šŸ’šŸ“§šŸ”²šŸˆšŸ“¹šŸ’«šŸŽ§ šŸŒŸšŸÆšŸ”­šŸŽæ šŸŽ¹šŸ—»šŸ’³šŸ”„šŸ•šŸ’‚ šŸ©šŸ‘ šŸŒ—šŸ¹ facilisis šŸ‘šŸ‘šŸ’¤šŸ•šŸžšŸ»šŸ© posuere šŸŽ‘šŸ¢šŸ‘šŸØšŸ“—šŸ‘£ ultrices. Vestibulum šŸŒ šŸ‘°šŸ’¼šŸ“šŸŗšŸ’« šŸ‘˜šŸ–šŸ”•šŸ”¤šŸ–šŸ’¶šŸ¢šŸ“µšŸ‘šŸŖ šŸ”øšŸŽæšŸ”¤šŸ”šŸ’”šŸŒ„šŸ“šŸ‘‰šŸŽŽšŸŽ†šŸŽ¢šŸ”’ šŸ““šŸ‘‰šŸŒ±šŸšŸŒ“šŸŽ†šŸ©šŸ€šŸ‘“šŸ’¹šŸŽ“ šŸ”“šŸŒ’šŸ”˜šŸ‘”šŸ•œ šŸŒšŸ‰šŸ‘šŸ®šŸŽøšŸ³šŸ’‰šŸŽ„ šŸ³šŸ²šŸ”­šŸ“†šŸŽšŸ”¼šŸŽšŸ©šŸ’¾šŸˆšŸŽ¶šŸ’…šŸœšŸ€. šŸ­šŸ„šŸŒ³šŸšŸ’šŸ‘ˆšŸŒ† šŸ”¦šŸ¦šŸ‘µšŸŒ¹šŸŠšŸŽšŸ“³šŸŒƒšŸ“˜šŸŒ·šŸ’ŽšŸ““šŸŽ¼ šŸŽ³šŸ”šŸ”‚šŸ—½ šŸ’…šŸ°šŸŠšŸ‘‚šŸŒ“ šŸ’šŸ•—šŸ˜šŸ”¼šŸ”°šŸ€ šŸŽ‚šŸ“»šŸ•›šŸ”šŸŽ„ vitae šŸ“ŽšŸ†šŸššŸŒ²šŸ° ipsum šŸ‘˜šŸ‘ŽšŸ“…šŸŽˆšŸŒ†šŸ’®šŸ”šŸŽ¤ šŸ’ŗšŸ’‰šŸ’‰šŸ‘šŸ”›šŸ›šŸŗšŸøšŸ“­ šŸ’ šŸ‘žšŸØšŸ’– integer šŸŒšŸ“€šŸ‚šŸšŸ¼ volutpat, condimentum elit šŸŽŒšŸŒ•šŸŠšŸ‘¼ šŸŒ›šŸ•œšŸŒššŸ•¤šŸŽ šŸ¢šŸ’ØšŸ‘“šŸ‘¤ duis amet šŸ“¹šŸ•ššŸ”šŸ§šŸŒ·šŸ„šŸ‘¦ šŸ” šŸ¬šŸ‘¬šŸ©šŸ“«šŸ§šŸŽ·šŸ”¢šŸ’†šŸŽ­šŸ”³šŸ‘ˆ šŸ”‡šŸ‘暟’ˆšŸ‘§šŸšŸ±šŸ”‰ in šŸŒšŸŽ²šŸŒ šŸŒŸšŸ€šŸ‘›šŸŒžšŸŽ§ sed. Tristique malesuada id šŸ†šŸ•šŸ•ššŸŽÆšŸŒ¶ šŸ“ŗšŸ˜šŸ€šŸ®šŸ”¶šŸ€šŸ„šŸ‘¬šŸ’žšŸŽƒšŸŒ™šŸŽ„šŸ”¦šŸ— šŸ‘˜šŸ‘£šŸ‚šŸŽŖšŸ”‚šŸŽ¾ šŸ‘ŽšŸ‘®šŸ’ˆšŸ—»šŸŒæšŸ’°šŸ“©šŸ”‹šŸ’­šŸ’ƒ šŸšŸ•‘šŸ”‹šŸ‘ šŸ†šŸˆšŸ‘°šŸŒ… orci nam šŸ”€šŸ• šŸ„šŸ£šŸ‘˜šŸ²šŸ’˜šŸ„ šŸ„šŸŽŠšŸŽÆšŸ‘¾šŸ“… šŸ‘›šŸŒ½šŸ«šŸ”ƒšŸ‘‹šŸ€šŸ‘¶šŸ’„šŸ”³ šŸ•„šŸ‘ŖšŸ‘‘šŸ‘Æ šŸ“šŸ’”šŸ” šŸ’¼šŸ”³šŸ’² šŸ‘¬šŸ”šŸœšŸ’˜šŸ”ŒšŸŒŽšŸƒšŸŒ¶šŸšŸÆšŸŽŗ šŸ”ŸšŸ“ØšŸ”œšŸŽ±šŸ’“šŸ”› accumsan šŸŽ¢šŸ­šŸ‰šŸ³šŸ•œšŸ†šŸ”—šŸ“šŸ‘æ šŸ—šŸ‘‘šŸ“œšŸŽšŸ‡šŸ•šŸŒ› šŸŽ“šŸŒ°šŸ‘£šŸ“†šŸŒ‹ šŸ‘ŒšŸ±šŸ’šŸ”‡šŸ†šŸŒžšŸ“šŸ’»šŸŒŗ dictumst šŸ“”šŸšŸŒšŸ’¤šŸ…šŸ””šŸŸšŸ“„šŸŒ“šŸŒ’šŸ…šŸ“ØšŸ”šŸ‘ŗšŸ¬šŸŸ šŸ”¹šŸ’³šŸØšŸ’”šŸŽ‹šŸ’•šŸ•œšŸ¦šŸ‘ŸšŸ•’šŸ•£šŸ’…šŸ’— šŸ¤šŸ”ˆšŸ“€šŸ“œšŸ“™šŸŒ šŸ“«šŸ•˜šŸ‘šŸ’¾šŸ“± purus šŸ•’šŸ•šŸ‘µšŸ„šŸ’—šŸ¤šŸ• pharetra adipiscing elit, non šŸ¬šŸ‘øšŸ‰šŸ‘‘ šŸŽ šŸŒ‡šŸ‘°šŸ’„ šŸŒ•šŸ—¼šŸ®šŸ’‡šŸ— šŸ“ŒšŸ¤šŸŒ²šŸ‘¹šŸ“Œ šŸŽšŸ•“šŸ“ŽšŸ¤šŸ’¾ tellus šŸ’†šŸØšŸ‘‚šŸ•ŸšŸ’ššŸŽ‹šŸŒ šŸ³ šŸ˜šŸ«šŸŽµšŸ“ššŸ“ŸšŸ”›šŸ‘šŸ­šŸ”„šŸ‘ŒšŸ“šŸ‘ššŸ„šŸž šŸ’šŸŠšŸ‘¾šŸ˜šŸ‘°šŸ“„šŸ’ÆšŸ”‘ proin šŸ”šŸ”šŸ³šŸŽ»šŸ¶šŸœ šŸ•šŸŒµšŸ“ÆšŸ”–šŸ’…šŸ•”šŸ’˜šŸšŸŒ¾šŸ’ØšŸ”²šŸ”¼šŸœšŸ˜šŸ•‚ in suscipit šŸŽšŸŽ„šŸŽ¬šŸ”™šŸ‘ŖšŸ’£šŸ£šŸ’ÆšŸ•§ lectus šŸŒ¾šŸššŸŗšŸ†šŸ’‰šŸŽ”šŸ‘· šŸ“–šŸ”…šŸ‘¼šŸ•ž šŸŒ„šŸŒƒšŸ“¦šŸ”²šŸ’˜šŸŒ¶šŸ’šŸÆšŸ’æ senectus šŸ‘»šŸ’ˆšŸ—½šŸˆ šŸ“œšŸ‰šŸ’šŸšŸ”–šŸ‘™šŸ”€šŸ…šŸ‘™ šŸ¬šŸ“·šŸŽØšŸ‘¹šŸŽ¬ šŸ·šŸŒšŸ”½šŸ’ØšŸŽæšŸŒŒšŸŒ’ šŸŽŽšŸŠšŸ”•šŸ. šŸˆšŸŒ„šŸ“§šŸŠšŸ“›šŸ‘—šŸ•Ÿ šŸ‹šŸ’ŒšŸ”šŸ›šŸ’«šŸ”°šŸ‘ƒšŸ•‘ ridiculus mattis šŸ•“šŸŒšŸ‘˜šŸŒ¹ šŸ‘…šŸ’šŸØšŸ”ÆšŸ‚šŸ•ƒšŸŒšŸ‘ šŸšŸ”” pellentesque elit eu, šŸ’šŸ§šŸ’ÆšŸ”„šŸ“ˆšŸ“›šŸ»šŸ“†šŸ”±šŸ““šŸ”øšŸ»šŸ˜šŸŽ€ viverra šŸŒ†šŸ‰šŸ‰šŸŒ† šŸ“ŖšŸ•šŸŠšŸŒœšŸ“ŗšŸ”†šŸ¢šŸŽƒ mi sed tellus luctus šŸœšŸƒšŸ”¶šŸ—½ laoreet dui tristique šŸ”†šŸŒøšŸ›šŸ”£šŸ¤šŸ“˜šŸ•œšŸƒšŸ‹ pretium ultrices šŸ”³šŸ‡šŸšŸŽ­šŸ€ šŸ±šŸ šŸ‘¬šŸ“®šŸŒ—šŸŒ†šŸ’ŗšŸ”†šŸ‘ØšŸŒ± et šŸ‘øšŸ“šŸ“©šŸ”ŒšŸ‘ÆšŸ‘šŸ‘«šŸ‘³šŸ’ø šŸŽšŸ’‰šŸ”±šŸ’¦šŸ‘“ šŸŖšŸ¶šŸøšŸ”¤ šŸ’”šŸ¤šŸ‘ŗšŸ‘»šŸ¤šŸŽ„šŸ½šŸ”¦šŸ‘ŒšŸ””šŸ“ššŸ’”šŸ”šŸŽ» šŸŽµšŸ‘”šŸ•€šŸŽ© šŸøšŸ’šŸ­šŸ• šŸ”¢šŸŽ§šŸššŸ’Ŗ šŸŒøšŸ°šŸ’šŸšŸŽ„šŸ•šŸ”¬šŸ’¶ šŸ’ƒšŸŒ½šŸ’•šŸ­ šŸ’ÆšŸšŸ“­šŸššŸ“›šŸ““šŸŒšŸ”ÆšŸ“¦ šŸ•šŸ‘¾šŸ“’šŸ“³šŸ’µ šŸ šŸ’ŗšŸ•”šŸ•šŸ“ƒ adipiscing nulla congue šŸ”–šŸ’²šŸ•ššŸŽ°šŸ”‹šŸ‘¬ sem šŸ‘½šŸ‘µšŸ‘œšŸ‘‡ vehicula šŸ“‘šŸŒŽšŸšŸ’ˆ consectetur nulla ullamcorper enim, šŸ«šŸƒšŸ¢šŸ”„šŸšŸ•¢šŸ‘–šŸ’ØšŸ‘ŗšŸ’°šŸ‘ŽšŸ’³šŸ šŸ¤ vel fermentum porttitor lacus šŸ“±šŸ’§šŸ”œšŸ”°šŸ‘±šŸŽ°šŸ‰šŸ”“šŸ•§šŸŒšŸ•™ šŸŽ“šŸ«šŸ±šŸŸšŸŒ–šŸ•žšŸ„šŸšŸ“œšŸ”ƒšŸˆšŸ””šŸšŸ”— šŸ’ŠšŸšŸ“šŸ‘­šŸŽ¢šŸ³šŸÆšŸ“·šŸ€šŸ”ƒ. šŸ¦šŸššŸ”µšŸ•œšŸ© id šŸŒ”šŸ”¤šŸ’暟Œ»šŸ¹ šŸŒŽšŸŽˆšŸ“¢šŸ”¬šŸ–šŸ’¢šŸ‘øšŸŽ­ šŸ¤šŸ”µšŸ”“šŸ••šŸ“ŖšŸ’¢šŸ”šŸ‘½šŸ’“ šŸ›šŸ‘¶šŸ”¢šŸŽ¹šŸ„šŸ‘œšŸ“ŒšŸ­šŸ”¼šŸŽ«šŸÆšŸŽ¦šŸ’ŽšŸ¦ šŸØšŸ’§šŸ“šŸŒŠšŸ” consequat pretium šŸ‘šŸ¬šŸ°šŸ‘–šŸ„šŸ“ŗšŸ‘›šŸŒ• šŸ„šŸ”±šŸ”©šŸšŸŒžšŸŒŗšŸŒšŸ‘‘ šŸ°šŸ•¢šŸ’±šŸ‘–šŸ¶šŸ„šŸ“ÆšŸŽ¶šŸ’§šŸ­šŸ”€šŸŽ¾šŸ©šŸ‘ massa, est šŸ‘¶šŸ­šŸ’…šŸ•”šŸ³šŸ’—šŸžšŸ’ššŸ©šŸ·šŸ˜šŸŒ„šŸ‡ šŸ¼šŸ‘€šŸ‘€šŸŽ… šŸ“„šŸŽšŸžšŸ’¼ placerat erat šŸ’§šŸŒ‰šŸ’»šŸ”£šŸ„šŸ“ šŸŖšŸ“»šŸƒšŸ”»šŸ‘ šŸ•˜šŸžšŸˆšŸ”šŸ““ dolor šŸ“šŸ’¹šŸŽšŸ‚šŸ‰ neque, šŸ‘—šŸšŸŖšŸŒµšŸ•›šŸ„ šŸ•šŸ‘”šŸ”¼šŸŽ”šŸ”ŗšŸ“¬ sed šŸ’ØšŸ’§šŸ¢šŸ¼šŸ‘˜šŸŒ³šŸŽ¼šŸ‘¹šŸ‰šŸ•• enim šŸ”šŸšŸ‘ŠšŸ’€šŸ”“ šŸ«šŸˆšŸ’€šŸŒ³šŸ”’šŸ‘µšŸ”˜šŸŽŗšŸ’“šŸ‘ šŸ‘­šŸ”²šŸ°šŸ’暟”ŖšŸŒŠ šŸŒ…šŸ•”šŸŽ‘šŸ“›šŸ”¶šŸ”˜šŸŽ‘šŸÆ šŸ²šŸ“ŗšŸ‘¬šŸ“ŠšŸ’ elit, šŸŒ½šŸŽ±šŸ’‡šŸŽ„ ultricies šŸ“”šŸ’²šŸ¦šŸŒšŸššŸŒµšŸµ šŸŽ®šŸ“§šŸ”ŸšŸ“šŸ‘•šŸ”šŸŒ“šŸ”ŠšŸ‘³šŸ—¼šŸ’’šŸŒ“šŸ‘šŸ“žšŸ”³šŸ‘œšŸ”„šŸšŸ¾šŸ§šŸŠ šŸŒ°šŸ—¾šŸŒ‚šŸ„ šŸ”›šŸ€šŸšŸžšŸ””šŸ“–šŸ’‰šŸ“¼šŸ„šŸ± šŸœšŸŽŗšŸµšŸ’暟‘‚šŸŒ‹šŸŒø šŸ”žšŸ¤šŸ”ŸšŸ€šŸ“™šŸ©šŸ‘‘ porta id šŸŽ„šŸ’ŗšŸ™šŸ‘¶šŸ‘ŖšŸ”ŖšŸ‘ŖšŸ­šŸ’ššŸ“—šŸŽ…šŸšŸ‘”šŸŽ­ šŸ¦šŸŽŒšŸ†šŸ’« quis nulla dictumst non šŸ“«šŸµšŸ”«šŸ•  šŸ”ÆšŸ”ƒšŸ·šŸ“–šŸ’™šŸ‘“šŸ’ šŸŽ¬šŸ•ƒšŸ„šŸ«šŸ›šŸŒ†šŸ—šŸ‘…šŸ“· šŸ“ššŸ­šŸŒžšŸŒŽšŸ•šŸ‘œšŸ‘³ šŸ§šŸ’¬šŸ’“šŸŽ†šŸ„šŸ” šŸ“„šŸ°šŸ“šŸŒˆ šŸŽ©šŸŒ‡šŸŒŸšŸ“™ suspendisse šŸ””šŸ‘«šŸšŸ©šŸŒ‰šŸ•ššŸ“˜šŸ® šŸ‘šŸšŸ‘®šŸŽ­šŸ£ šŸ‘°šŸ“¤šŸ™šŸˆšŸ‘“šŸ°šŸ¦ lacinia diam eu vestibulum donec faucibus šŸ”šŸŽ“šŸŒ·šŸ’©šŸ”šŸœšŸ’™ šŸŽšŸ”‰šŸŒ›šŸ“ šŸ¢šŸ“„šŸ†šŸŽ†. -interface Props { - title?: string; - description?: string | undefined; - navItems?: MenuItem[]; - preloadCatalogue?: boolean; -} - -const { title, description, navItems, preloadCatalogue } = Astro.props; -const canonicalURL = new URL(Astro.url.pathname, Astro.site); ---- - - - - - - - - Erika - - - - - - {preloadCatalogue && } - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
+ -
-
- +šŸ”²šŸ€šŸØšŸ‘†šŸ‘ŽšŸ©šŸ¦šŸŽ¹ nibh šŸ•žšŸƒšŸ”»šŸ“Ø nec pulvinar šŸ“šŸœšŸ’»šŸøšŸ¾šŸ¾šŸ’– risus šŸ«šŸ•œšŸ‘šŸŒ³šŸ“‡šŸ‹šŸŖšŸŽ£ neque šŸ‘šŸšŸŒ¹šŸ«šŸŒŒšŸ‘… šŸ‘¹šŸˆšŸ—½šŸ£ šŸ’‰šŸ“ŠšŸ˜šŸ”‰šŸ†šŸ’”šŸŒøšŸ‘°šŸ”›šŸ“¼ šŸŗšŸŒæšŸŖšŸ”œšŸ’„šŸŽ’šŸ‘Ÿ amet vitae, morbi elit rhoncus šŸ™šŸ«šŸŖšŸŽ”šŸ‘•šŸ’µ šŸŒ•šŸ’šŸ’ÆšŸ·šŸŒ¾šŸ“¼šŸ€šŸ¬šŸŒ›šŸ•¤šŸŠšŸ‘”šŸ”©šŸ‚šŸ“ššŸ’µ šŸ’–šŸšŸ‘¹šŸ”¼šŸ šŸ¢šŸŽ¼šŸ§ šŸ‘›šŸ“©šŸÆšŸ’Š šŸ“žšŸŒ’šŸ“žšŸ’½ purus šŸ”šŸ“¼šŸ“¬šŸŒžšŸšŸ’ø morbi šŸšŸŽ¾šŸŽ”šŸŒ‹ šŸ“ØšŸŒˆšŸ”ˆšŸŒ†šŸ”ØšŸ“•šŸ’›šŸ”šŸÆ šŸ’…šŸŽ£šŸ‘½šŸ•¦ šŸŒ“šŸ‹šŸ”šŸ”‘ ut congue šŸ”ŠšŸ§šŸŒ»šŸ•‘ gravida šŸ‰šŸ‘…šŸ‘¦šŸ‘¢šŸŽ‰šŸ”ŽšŸ’ŖšŸ”„šŸŽˆ šŸ‘³šŸ”šŸ•„šŸŽ‚ šŸ”µšŸ˜šŸ” šŸ‘šŸ‘‰šŸ”€šŸ“ŠšŸ” šŸŒ„šŸÆšŸ’½šŸ“šŸ“ššŸ†šŸ‘†šŸŒ‚šŸŽ”šŸ“–šŸŽ±šŸ‘®šŸŒ½šŸ„ orci šŸ“ššŸ£šŸ€šŸŽ¦šŸ“ŖšŸ’¶šŸŒ“ etiam šŸŒ‘šŸšŸ’‡šŸ‘¬šŸ“šŸ“…šŸ’øšŸ‘ŸšŸŒ•šŸŠšŸŽšŸŖ vehicula sed šŸ“’šŸ“­šŸ“£šŸŒŒšŸšŸŽ²šŸŒ“šŸ šŸ”šŸ‘ÆšŸ“„šŸ’½šŸŒ—šŸ’²šŸ”šŸ”« šŸŽˆšŸ„šŸ‡šŸ”ŗšŸ’šŸ’šŸŒ³šŸ‘ŽšŸŽ¤šŸ®šŸ“­šŸ“Š šŸ“šŸ‘ šŸ•žšŸ•˜šŸ‚šŸ£šŸŗšŸ¬šŸ– eget lectus šŸ„šŸšŸ“‰šŸ“„šŸŒ¾šŸŽ“šŸ£ šŸ¾šŸ•¤šŸ¼šŸŒƒšŸ”©šŸ‚šŸ•£šŸ‰šŸ’§šŸ“ŠšŸŽ§šŸŽ§šŸŒ‚šŸŽ  šŸµšŸŒŗšŸ“°šŸ“‘šŸ° šŸ‘£šŸøšŸ’ššŸ—šŸ”œšŸ••šŸ šŸ•™šŸ‡šŸ“²šŸŒ™ šŸ‘«šŸ’›šŸ’½šŸ‘šŸ’ø šŸ”šŸ”šŸ”˜šŸŽŖšŸ’»šŸ”‚ nunc, šŸ¹šŸ•—šŸ”šŸ“¤šŸŽ· sem vitae adipiscing tempor, šŸ•”šŸššŸˆšŸŒŸšŸ‘ŽšŸ’¢šŸ”¦ šŸŒ“šŸ’暟’”šŸŽ³šŸ“šŸŒ½šŸŽ’šŸ”­šŸ”Ø lectus šŸŒ°šŸŒ“šŸ—½šŸ’€šŸˆ est šŸ“¬šŸ’‘šŸ•šŸŗ šŸ“€šŸ®šŸ”«šŸ”œšŸŽ­šŸŒ·šŸ€šŸ’‘šŸ‚šŸ”µ vulputate leo eget šŸ—šŸŒ“šŸŽƒšŸ”£šŸ‘²šŸ“™ šŸ“ŗšŸˆšŸšŸ’¦šŸŒ…šŸ’”šŸ’Œ phasellus šŸ‘ØšŸ’”šŸ”ÆšŸƒšŸœšŸ’šŸ”µšŸ’†šŸ©šŸ¦šŸ¬šŸ…šŸ§ šŸŽ²šŸ°šŸ’ŠšŸ£šŸ“šŸ’Ž šŸ”®šŸŽ‰šŸŽ±šŸ‘暟ŸšŸ’ŖšŸ•¤ šŸ”šŸœšŸ•ššŸŒ. Turpis vulputate šŸŒ—šŸ”«šŸ“™šŸŽ½šŸŽ½šŸŽæšŸ““ pretium congue in arcu tincidunt. Nisi šŸ“ŗšŸ’šŸ‘ƒšŸ•ƒšŸ« šŸšŸ“ØšŸšŸ••šŸ’ÆšŸ’­ šŸ“¬šŸ§šŸ”§šŸŒŸ šŸ©šŸ‘›šŸ­šŸŒ½šŸŽ®šŸŒ magnis porttitor šŸ”ˆšŸŽ„šŸŒ“šŸ‘¶šŸ®. šŸ‘¢šŸŒµšŸ¬šŸŒšŸ© rutrum egestas šŸ’™šŸ” šŸŽ§šŸœšŸŽ£ nisi lectus feugiat šŸ€šŸ•ššŸ•¢šŸŒ€šŸŽ°šŸ’… šŸ’šŸ“®šŸŒšŸ“ƒšŸ”ˆ šŸŽ“šŸ“šŸ®šŸ„šŸ“¢šŸ“›šŸŗšŸ”ŠšŸ’ sagittis šŸ–šŸŒ‚šŸŽ“šŸ‘’šŸ‘ŽšŸ”¼šŸ‘ŠšŸ“£šŸ“­šŸ‘暟¦šŸ”–šŸµšŸ’ŗšŸ³ šŸ•—šŸ”­šŸ­šŸ“šŸ‘šŸ’Æ massa erat šŸ§šŸšŸŽ¤šŸ‘”šŸ’‘šŸ£šŸ¢ šŸšŸ—¾šŸ”™šŸŠšŸŽ­šŸ”£šŸ‘ šŸ’ŠšŸ’–šŸŒ³šŸ’ŒšŸ’暟ÆšŸ”“šŸŽŖ. Id šŸ…šŸ¦šŸ’šŸ“±šŸ’šŸ‘“šŸŽ” ut šŸ¬šŸ””šŸŒŸšŸŒ‘ šŸŽ¦šŸ’®šŸŽ©šŸ”¬ šŸ‘°šŸ“µšŸ˜šŸŽ“ šŸ‘ŖšŸ©šŸ‘³šŸ’†šŸ§ purus šŸ’®šŸ¦šŸ¼šŸŽ·šŸ”¦ šŸŽŗšŸ”‡šŸ“šŸ“ˆ cras pretium volutpat, etiam risus šŸ‡šŸ•”šŸŖšŸ”½ šŸ‘ šŸ”®šŸ”ˆšŸŽƒšŸŽ§šŸŒ„šŸ‘œ vel sapien šŸ’ÆšŸ‘»šŸ‘œšŸŽ¼šŸ“œ šŸŽ½šŸ’€šŸŠšŸŒ‰šŸ““šŸ»šŸ“šŸ’‰šŸ“ŗšŸŗ vivamus lorem šŸ“ƒšŸ“‰šŸ”žšŸ•¦ šŸ“£šŸØšŸŒ‰šŸ”©šŸŗšŸ”ŽšŸ‘™ molestie tellus šŸ‘¹šŸ’ƒšŸ••šŸ“—šŸ”µšŸ•¢ vel šŸ“ŽšŸšŸ”…šŸ“šŸ”šŸššŸŒ€šŸ’šŸ¦ šŸŽ±šŸ®šŸ•£šŸ‘‹šŸ“³šŸŽ‘ šŸ•™šŸ”šŸ•’šŸ“–šŸ“ŖšŸ‘© condimentum šŸ¤šŸ’šŸ’·šŸ•žšŸ’¬šŸ’šŸŽØšŸ’° amet nisl fringilla bibendum šŸ˜šŸƒšŸŽƒšŸ‰šŸ°šŸ¦šŸŽšŸŽ±šŸ…šŸŽ„šŸ”³šŸŽµšŸ šŸ§šŸ–šŸ”­šŸ’‡ šŸ•žšŸŽ±šŸ“‚šŸˆšŸ‘‡ šŸÆšŸ‘šŸŽ¹šŸ‘˜šŸ’ÆšŸ“—šŸ‘· šŸ’‚šŸ•˜šŸ‘¦šŸ’˜šŸ’†šŸŒ—šŸ•ƒšŸ€šŸ”š šŸ”œšŸ’ƒšŸŒ’šŸ§šŸ”šŸ¹šŸ”‘šŸ’‚šŸ‘œšŸ­ šŸŽ¤šŸ‘ŒšŸ‘šŸ©šŸ“žšŸ•¦šŸ”œšŸ™ morbi šŸ‘‘šŸøšŸŒ„šŸ¹šŸƒšŸ¢šŸ³šŸ’ø malesuada quam amet, šŸ’°šŸ”—šŸ‘—šŸ°šŸ†šŸ•‘šŸ“® šŸ‹šŸŒ˜šŸžšŸ§ šŸ”»šŸŽŗšŸ˜šŸ‘šŸ¬šŸ”· pulvinar šŸ”­šŸ¬šŸ‘¦šŸ’† vivamus tempus šŸ§šŸ‘‰šŸ•¢šŸ“­šŸ” šŸŒ”šŸ•§šŸ’§šŸ“ŠšŸ”¼ šŸ‘¬šŸ‘šŸŒ˜šŸ®šŸŽŽšŸšŸ•ƒšŸ‘—šŸ”“šŸ½šŸ˜šŸŒˆšŸ“ŗšŸ‘™šŸ•. -
- Powered by Astro
- Source Code
- Changelog -
-
-
+
- - - -
- - - -` +Faucibus šŸŽˆšŸ‹šŸ”„šŸ“‡šŸ”šŸ’ šŸŽ¾šŸŽ©šŸ”¹šŸ”£šŸŽšŸøšŸŒ³ vestibulum, šŸ¢šŸŒ˜šŸ•œšŸ‘‚šŸ’¬šŸŽ‘šŸŖ šŸ“«šŸ“ŠšŸŽ…šŸŒ·šŸ“šŸ”°šŸ£šŸ’­šŸ‘§šŸ‘½šŸŽ’šŸ“•šŸ’“šŸ‘Æ šŸŽŽšŸšŸ•„šŸ•‘šŸ’—šŸŒšŸ“©šŸ“§šŸøšŸŒ™ šŸ•šŸµšŸ€šŸ«šŸŽ«šŸ”°šŸ‘²šŸ›šŸ”µšŸŖ šŸ³šŸ†šŸŽ·šŸ quam šŸ’ šŸŽˆšŸ•“šŸŒ“šŸŒ±šŸØšŸ’¢šŸ®šŸ•”šŸ””šŸ’ŽšŸ imperdiet placerat šŸ”±šŸ‘šŸ“”šŸ”§šŸŒ nisl šŸ“¢šŸ—»šŸ¹šŸ”šŸ••šŸšŸ’¦ šŸ“ˆšŸ”µšŸ““šŸ³šŸ“¬šŸ’•šŸ“§šŸ““šŸš šŸ“ˆšŸŒøšŸ”±šŸ’œšŸ’ŽšŸŒšŸ»šŸ“˜šŸ šŸ’µšŸ”šŸ”ŒšŸ“¦šŸ‘šŸ©šŸ”‡šŸ‘…šŸ“ŽšŸ† šŸŒšŸ’žšŸ“ŗšŸ«šŸ·šŸŒšŸ’’šŸŒøšŸ”ŽšŸŒ‡šŸ“ šŸ”‚šŸŒ¼šŸ’ŽšŸŸ ut vel et šŸŽ©šŸ‘–šŸ’¾šŸ‘¢šŸŽµšŸ’‚ šŸŒ‚šŸ“±šŸ’³šŸØšŸ² šŸ”šŸ”µšŸƒšŸŽ¦šŸ•šŸŒŸšŸŒšŸ”‘ tristique vel šŸŒƒšŸ’‹šŸ‘‰šŸ”°. Tortor sit šŸŒ“šŸ‘‘šŸ”“šŸ€šŸŒ¹ tempus šŸøšŸ¹šŸ“”šŸŽ‚šŸŗšŸ€ consequat ornare šŸ‘½šŸ‘½šŸƒšŸ“—šŸŒ˜šŸ šŸ”ÆšŸŒ²šŸ“šŸ“„šŸšŸ£šŸø šŸ”šŸ“šŸ“žšŸ£ šŸ’©šŸ”„šŸ’ØšŸ‘‹šŸ”¹ šŸŒ•šŸ’ŠšŸŖšŸ•” šŸ‡šŸ‰šŸµšŸ‘¢šŸŽ³šŸ•›šŸø šŸˆšŸ‡šŸ­šŸ•šŸ¬ rhoncus šŸ“›šŸšŸ”ØšŸ’¶ bibendum šŸŽ‹šŸ‘²šŸ¤šŸ“°šŸ šŸŒøšŸ“™šŸšŸŒ  šŸŽæšŸŽ€šŸ‘”šŸ’²šŸ“‹šŸ’¦šŸµšŸ”‘šŸ•”šŸ•žšŸ„šŸšŸ‘§šŸ”˜šŸ’” arcu šŸ’£šŸ‘šŸŒ¶šŸ‘¬šŸŒ¹šŸ”’šŸŒšŸ“ šŸ•–šŸŽ“šŸ“ŒšŸŽ©šŸ“«šŸ’¬ šŸ‘‹šŸŒššŸŒ¶šŸ’¶šŸŠšŸ’«šŸ”šŸ“²šŸŽŗšŸ®šŸ’™šŸŸ šŸ•¦šŸŒšŸ”šŸµšŸ’ šŸšŸœšŸŖšŸ”³šŸ“žšŸ’šŸ’»šŸŽ¶šŸ“¦šŸ”µšŸ“ÆšŸ¦šŸŽ lobortis malesuada šŸ’‡šŸ’øšŸ°šŸ’…. šŸŒšŸ•šŸ‚šŸ“‡ šŸŽ’šŸ’ØšŸ”™šŸ‰šŸŽ¹šŸ”„šŸ”—šŸ““šŸ‘„šŸŽˆšŸ“’šŸ”øšŸ’šŸ”‡šŸŒ™šŸ•šŸŠšŸ£šŸ’†šŸ’—šŸ”½ tortor šŸ”µšŸššŸ“šŸŒ±šŸŒ†šŸ€šŸ» šŸ”“šŸ‘¦šŸŒšŸŒ”šŸÆšŸ‘šŸ•£ šŸŒ…šŸ‘‡šŸ“šŸ’°šŸ’ condimentum šŸ‹šŸ’‰šŸžšŸ“†šŸ²šŸ‘¢šŸ¬šŸ’ŒšŸŽ¤ šŸŽ¢šŸ‘·šŸ‘‘šŸ‘† šŸ’±šŸŽ’šŸ¬šŸŽ« šŸ—¾šŸ’šŸ‘ŽšŸ‘„ šŸ’ŠšŸ”…šŸ”™šŸ®šŸ—šŸ„ nulla adipiscing šŸŽ¦šŸ‘暟žšŸ”‹šŸ“œšŸ‘µ šŸ„šŸ·šŸŽµšŸ‘¾ šŸŽæšŸ’šŸŒ²šŸ’„šŸ“ššŸŒ”šŸ“­šŸ‘„šŸ‘暟±šŸ“·šŸ’®šŸ”€šŸ„ velit.` for i := 0; i < b.N; i++ { h := handler.NewHandler(source, "AstroBenchmark") var doc *astro.Node diff --git a/internal/sourcemap/sourcemap.go b/internal/sourcemap/sourcemap.go index 463fae59..4d7b9781 100644 --- a/internal/sourcemap/sourcemap.go +++ b/internal/sourcemap/sourcemap.go @@ -468,6 +468,7 @@ type LineOffsetTable struct { // as an optimization. byteOffsetToFirstNonASCII int columnsForNonASCII []int + utf16LineLength int } func GenerateLineOffsetTables(contents string, approximateLineCount int) []LineOffsetTable { @@ -508,10 +509,17 @@ func GenerateLineOffsetTables(contents string, approximateLineCount int) []LineO continue } + if c <= 0xFFFF { + column++ + } else { + column += 2 + } + lineOffsetTables = append(lineOffsetTables, LineOffsetTable{ byteOffsetToStartOfLine: int(lineByteOffset), byteOffsetToFirstNonASCII: ByteOffsetToFirstNonASCII, columnsForNonASCII: ColumnsForNonASCII, + utf16LineLength: column, }) columnByteOffset = 0 ByteOffsetToFirstNonASCII = 0 @@ -544,6 +552,7 @@ func GenerateLineOffsetTables(contents string, approximateLineCount int) []LineO byteOffsetToStartOfLine: int(lineByteOffset), byteOffsetToFirstNonASCII: ByteOffsetToFirstNonASCII, columnsForNonASCII: ColumnsForNonASCII, + utf16LineLength: column, }) return lineOffsetTables } @@ -639,6 +648,22 @@ func (b *ChunkBuilder) GetLineAndColumnForLocation(location loc.Loc) []int { return []int{originalLine + 1, originalColumn + 1} } +func (b *ChunkBuilder) OffsetAt(location loc.Loc) int { + lineAndColumn := b.GetLineAndColumnForLocation(location) + line := lineAndColumn[0] - 1 + column := lineAndColumn[1] - 1 + + // Collect the length of every line before this one + offset := 0 + for i := 0; i < line; i++ { + currentLine := b.lineOffsetTables[i] + offset += currentLine.utf16LineLength + } + + // Add the column within this line + return offset + column +} + func (b *ChunkBuilder) AddSourceMapping(location loc.Loc, output []byte) { if location == b.prevLoc { return From 2b2a8da47ee49ffbb4cd6bfd688a4ec36b6a394b Mon Sep 17 00:00:00 2001 From: Princesseuh <3019731+Princesseuh@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:46:24 +0200 Subject: [PATCH 4/4] chore: changeset --- .changeset/selfish-dogs-love.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/selfish-dogs-love.md diff --git a/.changeset/selfish-dogs-love.md b/.changeset/selfish-dogs-love.md new file mode 100644 index 00000000..b7ef144a --- /dev/null +++ b/.changeset/selfish-dogs-love.md @@ -0,0 +1,5 @@ +--- +"@astrojs/compiler": patch +--- + +Adjust TSX output to return ranges using UTF-16 code units, as it would in JavaScript