├── .npmignore
├── jest.config.cjs
├── .gitignore
├── tsconfig.json
├── src
├── test
│ ├── src.css
│ ├── expected
│ │ ├── foo
│ │ │ └── dist
│ │ │ │ ├── _astro
│ │ │ │ └── style.css
│ │ │ │ ├── foo.html
│ │ │ │ ├── index.html
│ │ │ │ └── foo
│ │ │ │ └── index.html
│ │ └── dist
│ │ │ ├── _astro
│ │ │ └── style.css
│ │ │ ├── foo.html
│ │ │ ├── index.html
│ │ │ └── foo
│ │ │ └── index.html
│ ├── index.test.ts
│ └── src.html
└── index.ts
├── LICENSE
├── package.json
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | !dist/
2 | src/
3 |
--------------------------------------------------------------------------------
/jest.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('ts-jest').JestConfigWithTsJest} */
2 | module.exports = {
3 | preset: 'ts-jest',
4 | testEnvironment: 'node',
5 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/
2 | node_modules/
3 |
4 | # Logfiles and tempfiles
5 | *.log
6 | /log/*
7 | !/log/.keep
8 | /tmp
9 |
10 | # Other unneeded files
11 | *.swp
12 | *~
13 | .project
14 | .DS_Store
15 | .idea
16 | .secret
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "compilerOptions": {
4 | "strict": true,
5 | "declaration": true,
6 | "moduleResolution": "Node16",
7 | "esModuleInterop": true,
8 | "allowJs": false,
9 | "module": "Node16",
10 | "target": "ES2022",
11 | "outDir": "./dist",
12 | "skipLibCheck": true,
13 | "verbatimModuleSyntax": false
14 | },
15 | "include": ["src"],
16 | "exclude": ["src/**/*.test.ts"]
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/src.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --foo:
3 | url(/assets/images/foo.jpg)
4 | url("/assets/images/foo.jpg")
5 | url('/assets/images/foo.jpg')
6 | url(/foo/assets/images/foo.jpg)
7 | url("/foo/assets/images/foo.jpg")
8 | url('/foo/assets/images/foo.jpg')
9 | url(
10 | /assets/images/foo.jpg
11 | )
12 | url(
13 | "/assets/images/foo.jpg"
14 | )
15 | url(" /assets/images/foo.jpg ")
16 | url(
17 | '/assets/images/foo.jpg'
18 | )
19 | url(' /assets/images/foo.jpg ')
20 | url(
21 | /foo/assets/images/foo.jpg
22 | )
23 | url(
24 | "/foo/assets/images/foo.jpg"
25 | )
26 | url(" /foo/assets/images/foo.jpg ")
27 | url(
28 | '/foo/assets/images/foo.jpg'
29 | )
30 | url(' /foo/assets/images/foo.jpg ')
31 | url(./assets/images/foo.jpg)
32 | url(https://example.com/foo.jpg)
33 | url(//example.com/foo.jpg)
34 | /assets/images/foo.jpg
35 | /foo/assets/images/foo.jpg;
36 | }
--------------------------------------------------------------------------------
/src/test/expected/foo/dist/_astro/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --foo:
3 | url(/assets/images/foo.jpg)
4 | url("/assets/images/foo.jpg")
5 | url('/assets/images/foo.jpg')
6 | url(../assets/images/foo.jpg)
7 | url("../assets/images/foo.jpg")
8 | url('../assets/images/foo.jpg')
9 | url(
10 | /assets/images/foo.jpg
11 | )
12 | url(
13 | "/assets/images/foo.jpg"
14 | )
15 | url(" /assets/images/foo.jpg ")
16 | url(
17 | '/assets/images/foo.jpg'
18 | )
19 | url(' /assets/images/foo.jpg ')
20 | url(
21 | ../assets/images/foo.jpg
22 | )
23 | url(
24 | "../assets/images/foo.jpg"
25 | )
26 | url(" ../assets/images/foo.jpg ")
27 | url(
28 | '../assets/images/foo.jpg'
29 | )
30 | url(' ../assets/images/foo.jpg ')
31 | url(./assets/images/foo.jpg)
32 | url(https://example.com/foo.jpg)
33 | url(//example.com/foo.jpg)
34 | /assets/images/foo.jpg
35 | /foo/assets/images/foo.jpg;
36 | }
--------------------------------------------------------------------------------
/src/test/expected/dist/_astro/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --foo:
3 | url(../assets/images/foo.jpg)
4 | url("../assets/images/foo.jpg")
5 | url('../assets/images/foo.jpg')
6 | url(../foo/assets/images/foo.jpg)
7 | url("../foo/assets/images/foo.jpg")
8 | url('../foo/assets/images/foo.jpg')
9 | url(
10 | ../assets/images/foo.jpg
11 | )
12 | url(
13 | "../assets/images/foo.jpg"
14 | )
15 | url(" ../assets/images/foo.jpg ")
16 | url(
17 | '../assets/images/foo.jpg'
18 | )
19 | url(' ../assets/images/foo.jpg ')
20 | url(
21 | ../foo/assets/images/foo.jpg
22 | )
23 | url(
24 | "../foo/assets/images/foo.jpg"
25 | )
26 | url(" ../foo/assets/images/foo.jpg ")
27 | url(
28 | '../foo/assets/images/foo.jpg'
29 | )
30 | url(' ../foo/assets/images/foo.jpg ')
31 | url(./assets/images/foo.jpg)
32 | url(https://example.com/foo.jpg)
33 | url(//example.com/foo.jpg)
34 | /assets/images/foo.jpg
35 | /foo/assets/images/foo.jpg;
36 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Kite
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-relative-links",
3 | "type": "module",
4 | "version": "0.4.2",
5 | "description": "Build Astro with relative links.",
6 | "scripts": {
7 | "build": "tsc",
8 | "dev": "tsc --watch",
9 | "test": "jest",
10 | "prepublishOnly": "npm run build"
11 | },
12 | "author": "Kite",
13 | "license": "MIT",
14 | "exports": {
15 | ".": "./dist/index.js"
16 | },
17 | "types": "./dist/index.d.ts",
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/ixkaito/astro-relative-links.git"
21 | },
22 | "keywords": [
23 | "astro",
24 | "withastro",
25 | "astro-component",
26 | "astro-integration",
27 | "renderer",
28 | "relative-link"
29 | ],
30 | "bugs": {
31 | "url": "https://github.com/ixkaito/astro-relative-links/issues"
32 | },
33 | "homepage": "https://github.com/ixkaito/astro-relative-links#readme",
34 | "dependencies": {
35 | "glob": "^10.3.10"
36 | },
37 | "devDependencies": {
38 | "astro": "^3.2.0",
39 | "@types/html-escaper": "^3.0.0",
40 | "@types/jest": "^29.5.5",
41 | "@types/node": "^20.8.0",
42 | "jest": "^29.7.0",
43 | "ts-jest": "^29.1.1",
44 | "typescript": "^5.2.2"
45 | },
46 | "peerDependencies": {
47 | "astro": ">=3.0.0"
48 | },
49 | "packageManager": "pnpm@9.1.0+sha512.67f5879916a9293e5cf059c23853d571beaf4f753c707f40cb22bed5fb1578c6aad3b6c4107ccb3ba0b35be003eb621a16471ac836c87beb53f9d54bb4612724"
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/index.test.ts:
--------------------------------------------------------------------------------
1 | import { writeFileSync, readFileSync } from 'fs';
2 | import path from 'path';
3 | import { leadingTrailingSlash, replaceCSS, replaceHTML } from '..';
4 |
5 | test.each([
6 | [undefined, '/'],
7 | ['', '/'],
8 | ['/', '/'],
9 | ['foo', '/foo/'],
10 | ['/foo', '/foo/'],
11 | ['/foo/', '/foo/'],
12 | ['//foo//', '/foo/'],
13 | ['foo/bar', '/foo/bar/'],
14 | ['/foo/bar', '/foo/bar/'],
15 | ['foo/bar/', '/foo/bar/'],
16 | ['/foo/bar/', '/foo/bar/'],
17 | ['//foo/bar//', '/foo/bar/'],
18 | ])('Leading and trailing slashed base', (base, expected) => {
19 | expect(leadingTrailingSlash(base)).toBe(expected);
20 | });
21 |
22 | test.each([
23 | {
24 | base: '/',
25 | file: 'index.html',
26 | },
27 | {
28 | base: '/',
29 | file: 'foo.html',
30 | },
31 | {
32 | base: '/',
33 | file: 'foo/index.html',
34 | },
35 | {
36 | base: '/foo/',
37 | file: 'index.html',
38 | },
39 | {
40 | base: '/foo/',
41 | file: 'foo.html',
42 | },
43 | {
44 | base: '/foo/',
45 | file: 'foo/index.html',
46 | },
47 | ])('Replaced HTML', ({ file, base }) => {
48 | const outDirPath = '/dist/';
49 | const filePath = outDirPath + file;
50 |
51 | expect(
52 | replaceHTML({
53 | outDirPath,
54 | filePath,
55 | base,
56 | html: readFileSync(path.resolve(__dirname, 'src.html'), 'utf-8'),
57 | })
58 | ).toBe(
59 | readFileSync(path.resolve(__dirname, 'expected' + base + filePath), 'utf-8')
60 | );
61 | });
62 |
63 | test.each([
64 | {
65 | base: '/',
66 | file: '_astro/style.css',
67 | },
68 | {
69 | base: '/foo/',
70 | file: '_astro/style.css',
71 | },
72 | ])('Replaced CSS', ({ base, file }) => {
73 | const outDirPath = '/dist/';
74 | const filePath = outDirPath + file;
75 |
76 | expect(
77 | replaceCSS({
78 | outDirPath,
79 | filePath,
80 | base,
81 | css: readFileSync(path.resolve(__dirname, 'src.css'), 'utf-8'),
82 | })
83 | ).toBe(
84 | readFileSync(path.resolve(__dirname, 'expected' + base + filePath), 'utf-8')
85 | );
86 | });
87 |
--------------------------------------------------------------------------------
/src/test/expected/foo/dist/foo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
48 | /
49 | /foo/
50 | /foobar/
51 | /foo/bar/
52 | /foo/baz/
53 | /foo/baz/
56 | /foo/baz/
57 | /foo/baz/
58 |
61 | /foo/baz/
62 |
63 | /foo/baz/
64 | example
65 | example
66 | parent
67 | foo
68 |
74 |
80 |
81 |
82 |
<a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |
74 |
80 |
81 |
82 | <a href="/foo/bar/">bar</a>
83 | 84 | 85 |