Skip to content

Commit

Permalink
Better handling for special characters (#496)
Browse files Browse the repository at this point in the history
* fix: better handling for special characters

* chore: prettier format

Co-authored-by: Nate Moore <nate@astro.build>
  • Loading branch information
natemoo-re and natemoo-re authored Aug 11, 2022
1 parent b10eb65 commit 76fcef3
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-starfishes-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': patch
---

Better handling for imports which use special characters
19 changes: 15 additions & 4 deletions internal/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,16 +390,27 @@ func matchNodeToImportStatement(doc *astro.Node, n *astro.Node) *ImportMatch {
return match
}

func safeURL(pathname string) string {
// url.PathEscape also escapes `/` to `%2F`, but we don't want that!
escaped := strings.ReplaceAll(url.PathEscape(pathname), "%2F", "/")
return escaped
}

func resolveIdForMatch(match *ImportMatch, opts *TransformOptions) string {
if strings.HasPrefix(match.Specifier, ".") && len(opts.Pathname) > 0 {
u, err := url.Parse(opts.Pathname)
pathname := safeURL(opts.Pathname)
u, err := url.Parse(pathname)
if err == nil {
ref, _ := url.Parse(match.Specifier)
spec := safeURL(match.Specifier)
ref, _ := url.Parse(spec)
ou := u.ResolveReference(ref)
return ou.String()
unescaped, _ := url.PathUnescape(ou.String())
fmt.Println(unescaped)
return unescaped
}
}
return ""
// If we can't manipulate the URLs, fallback to the exact specifier
return match.Specifier
}

func eachImportStatement(doc *astro.Node, cb func(stmt js_scanner.ImportStatement) bool) {
Expand Down
87 changes: 87 additions & 0 deletions packages/compiler/test/client-directive/special-characters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { test } from 'uvu';
import * as assert from 'uvu/assert';
import { transform } from '@astrojs/compiler';

const FIXTURE = `
---
import CaretCounter from '../components/^--with-carets/Counter';
import RocketCounter from '../components/and-rockets-🚀/Counter';
import PercentCounter from '../components/now-100%-better/Counter';
import SpaceCounter from '../components/with some spaces/Counter';
import RoundBracketCounter from '../components/with-(round-brackets)/Counter';
import SquareBracketCounter from '../components/with-[square-brackets]/Counter';
import RemoteComponent from 'https://test.com/components/with-[wacky-brackets}()10%-cooler/Counter';
---
<html>
<body>
<h1>Special chars in component import paths from an .astro file</h1>
<CaretCounter id="caret" client:visible />
<RocketCounter id="rocket" client:visible />
<PercentCounter id="percent" client:visible />
<SpaceCounter id="space" client:visible />
<RoundBracketCounter id="round-bracket" client:visible />
<SquareBracketCounter id="square-bracket" client:visible />
<RemoteComponent id="remote-component" client:visible />
</body>
</html>
`;

let result;
test.before(async () => {
result = await transform(FIXTURE, { experimentalStaticExtraction: true, pathname: '/@fs/users/astro/apps/pacman/src/pages/index.astro' });
});

test('does not panic', () => {
assert.ok(result.code);
});

test('hydrated components with carets', () => {
let components = result.hydratedComponents;
assert.equal(components[0].exportName, 'default');
assert.equal(components[0].specifier, '../components/^--with-carets/Counter');
assert.equal(components[0].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/^--with-carets/Counter');
});

test('hydrated components with rockets', () => {
let components = result.hydratedComponents;
assert.equal(components[1].exportName, 'default');
assert.equal(components[1].specifier, '../components/and-rockets-🚀/Counter');
assert.equal(components[1].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/and-rockets-🚀/Counter');
});

test('hydrated components with percent', () => {
let components = result.hydratedComponents;
assert.equal(components[2].exportName, 'default');
assert.equal(components[2].specifier, '../components/now-100%-better/Counter');
assert.equal(components[2].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/now-100%-better/Counter');
});

test('hydrated components with spaces', () => {
let components = result.hydratedComponents;
assert.equal(components[3].exportName, 'default');
assert.equal(components[3].specifier, '../components/with some spaces/Counter');
assert.equal(components[3].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/with some spaces/Counter');
});

test('hydrated components with round brackets', () => {
let components = result.hydratedComponents;
assert.equal(components[4].exportName, 'default');
assert.equal(components[4].specifier, '../components/with-(round-brackets)/Counter');
assert.equal(components[4].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/with-(round-brackets)/Counter');
});

test('hydrated components with square brackets', () => {
let components = result.hydratedComponents;
assert.equal(components[5].exportName, 'default');
assert.equal(components[5].specifier, '../components/with-[square-brackets]/Counter');
assert.equal(components[5].resolvedPath, '/@fs/users/astro/apps/pacman/src/components/with-[square-brackets]/Counter');
});

test('hydrated components with kitchen-sink', () => {
let components = result.hydratedComponents;
assert.equal(components[6].exportName, 'default');
assert.equal(components[6].specifier, 'https://test.com/components/with-[wacky-brackets}()10%-cooler/Counter');
assert.equal(components[6].resolvedPath, 'https://test.com/components/with-[wacky-brackets}()10%-cooler/Counter');
});

test.run();

0 comments on commit 76fcef3

Please sign in to comment.