astro-helmet 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +62 -0
- package/dist/index.test.js.map +1 -0
- package/package.json +3 -2
- package/src/index.test.ts +72 -0
- package/src/index.ts +6 -3
- package/tsconfig.json +5 -3
package/README.md
CHANGED
|
@@ -91,7 +91,10 @@ Default charset and viewport meta tags are included by default.
|
|
|
91
91
|
|
|
92
92
|
```ts
|
|
93
93
|
const DEFAULT_CHARSET = { charset: 'UTF-8' }
|
|
94
|
-
const DEFAULT_VIEWPORT = {
|
|
94
|
+
const DEFAULT_VIEWPORT = {
|
|
95
|
+
name: 'viewport',
|
|
96
|
+
content: 'width=device-width, initial-scale=1'
|
|
97
|
+
}
|
|
95
98
|
```
|
|
96
99
|
|
|
97
100
|
## Contributing
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ type BaseItem = {
|
|
|
3
3
|
priority?: number;
|
|
4
4
|
};
|
|
5
5
|
type ContentItem = BaseItem & {
|
|
6
|
-
innerHTML
|
|
6
|
+
innerHTML?: string;
|
|
7
7
|
};
|
|
8
8
|
export type HeadItems = {
|
|
9
9
|
title?: string;
|
|
@@ -16,4 +16,3 @@ export type HeadItems = {
|
|
|
16
16
|
export declare function renderHead(headItems: HeadItems[]): string;
|
|
17
17
|
export declare function renderAttrs(item: BaseItem | ContentItem): string;
|
|
18
18
|
export {};
|
|
19
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const DEFAULT_CHARSET = { charset: 'UTF-8' };
|
|
2
|
-
const DEFAULT_VIEWPORT = {
|
|
2
|
+
const DEFAULT_VIEWPORT = {
|
|
3
|
+
name: 'viewport',
|
|
4
|
+
content: 'width=device-width, initial-scale=1'
|
|
5
|
+
};
|
|
3
6
|
export function renderHead(headItems) {
|
|
4
7
|
const items = mergeHeadItems(headItems);
|
|
5
8
|
if (!items.title?.length)
|
|
@@ -122,7 +125,7 @@ function renderHeadTag(item) {
|
|
|
122
125
|
const attrs = renderAttrs(item);
|
|
123
126
|
return ['meta', 'link'].includes(item.tagName)
|
|
124
127
|
? `<${item.tagName} ${attrs} />`
|
|
125
|
-
: `<${item.tagName}${attrs && ' '}${attrs}>${item.innerHTML}</${item.tagName}>`;
|
|
128
|
+
: `<${item.tagName}${attrs && ' '}${attrs}>${item.innerHTML || ''}</${item.tagName}>`;
|
|
126
129
|
}
|
|
127
130
|
export function renderAttrs(item) {
|
|
128
131
|
return Object.entries(item)
|
|
@@ -136,3 +139,4 @@ export function renderAttrs(item) {
|
|
|
136
139
|
.filter((attr) => attr !== '')
|
|
137
140
|
.join(' ');
|
|
138
141
|
}
|
|
142
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { renderHead, renderAttrs } from './index';
|
|
3
|
+
describe('renderHead', () => {
|
|
4
|
+
it('should render the head tags in the correct order', () => {
|
|
5
|
+
const headItems = [
|
|
6
|
+
{
|
|
7
|
+
title: 'My Page',
|
|
8
|
+
meta: [{ name: 'description', content: 'My page description' }],
|
|
9
|
+
link: [{ rel: 'stylesheet', href: '/styles.css' }],
|
|
10
|
+
script: [{ src: '/script.js' }]
|
|
11
|
+
}
|
|
12
|
+
];
|
|
13
|
+
const expectedOutput = `<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
+
<title>My Page</title>
|
|
16
|
+
<script src="/script.js"></script>
|
|
17
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
18
|
+
<meta name="description" content="My page description" />`;
|
|
19
|
+
console.log(renderHead(headItems));
|
|
20
|
+
expect(renderHead(headItems)).toEqual(expectedOutput);
|
|
21
|
+
});
|
|
22
|
+
it('should throw an error if no title is provided', () => {
|
|
23
|
+
const headItems = [
|
|
24
|
+
{
|
|
25
|
+
meta: [{ name: 'description', content: 'My page description' }]
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
expect(() => renderHead(headItems)).toThrowError('Missing title tag.');
|
|
29
|
+
});
|
|
30
|
+
it('should deduplicate meta tags', () => {
|
|
31
|
+
const headItems = [
|
|
32
|
+
{
|
|
33
|
+
title: 'My Page',
|
|
34
|
+
meta: [
|
|
35
|
+
{ name: 'description', content: 'My page description' },
|
|
36
|
+
{ name: 'description', content: 'Duplicate description' }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
const expectedOutput = `<meta charset="UTF-8" />
|
|
41
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
42
|
+
<title>My Page</title>
|
|
43
|
+
<meta name="description" content="Duplicate description" />`;
|
|
44
|
+
expect(renderHead(headItems)).toEqual(expectedOutput);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('renderAttrs', () => {
|
|
48
|
+
it('should render boolean attributes correctly', () => {
|
|
49
|
+
const item = { async: true, src: '/script.js' };
|
|
50
|
+
expect(renderAttrs(item)).toEqual('async src="/script.js"');
|
|
51
|
+
});
|
|
52
|
+
it('should filter out invalid attributes', () => {
|
|
53
|
+
const item = {
|
|
54
|
+
innerHTML: '<p>Hello</p>',
|
|
55
|
+
priority: 1,
|
|
56
|
+
tagName: 'script',
|
|
57
|
+
src: '/script.js'
|
|
58
|
+
};
|
|
59
|
+
expect(renderAttrs(item)).toEqual('src="/script.js"');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAa,MAAM,SAAS,CAAA;AAE5D,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC3D,MAAM,SAAS,GAAgB;YAC9B;gBACC,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;gBAC/D,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;gBAClD,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC;aAC/B;SACD,CAAA;QAED,MAAM,cAAc,GAAG;;;;;0DAKiC,CAAA;QAExD,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;QAElC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACxD,MAAM,SAAS,GAAgB;YAC9B;gBACC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;aAC/D;SACD,CAAA;QAED,MAAM,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACvC,MAAM,SAAS,GAAgB;YAC9B;gBACC,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE;oBACL,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,qBAAqB,EAAE;oBACvD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,uBAAuB,EAAE;iBACzD;aACD;SACD,CAAA;QAED,MAAM,cAAc,GAAG;;;4DAGmC,CAAA;QAE1D,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,CAAA;QAC/C,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,IAAI,GAAG;YACZ,SAAS,EAAE,cAAc;YACzB,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,QAAQ;YACjB,GAAG,EAAE,YAAY;SACjB,CAAA;QACD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-helmet",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2",
|
|
5
5
|
"description": "A document head manager for astro.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"prettier": "^3.3.0",
|
|
26
|
-
"typescript": "^5.4.5"
|
|
26
|
+
"typescript": "^5.4.5",
|
|
27
|
+
"vitest": "^1.6.0"
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { renderHead, renderAttrs, HeadItems } from './index'
|
|
3
|
+
|
|
4
|
+
describe('renderHead', () => {
|
|
5
|
+
it('should render the head tags in the correct order', () => {
|
|
6
|
+
const headItems: HeadItems[] = [
|
|
7
|
+
{
|
|
8
|
+
title: 'My Page',
|
|
9
|
+
meta: [{ name: 'description', content: 'My page description' }],
|
|
10
|
+
link: [{ rel: 'stylesheet', href: '/styles.css' }],
|
|
11
|
+
script: [{ src: '/script.js' }]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
const expectedOutput = `<meta charset="UTF-8" />
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
17
|
+
<title>My Page</title>
|
|
18
|
+
<script src="/script.js"></script>
|
|
19
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
20
|
+
<meta name="description" content="My page description" />`
|
|
21
|
+
|
|
22
|
+
console.log(renderHead(headItems))
|
|
23
|
+
|
|
24
|
+
expect(renderHead(headItems)).toEqual(expectedOutput)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should throw an error if no title is provided', () => {
|
|
28
|
+
const headItems: HeadItems[] = [
|
|
29
|
+
{
|
|
30
|
+
meta: [{ name: 'description', content: 'My page description' }]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
expect(() => renderHead(headItems)).toThrowError('Missing title tag.')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should deduplicate meta tags', () => {
|
|
38
|
+
const headItems: HeadItems[] = [
|
|
39
|
+
{
|
|
40
|
+
title: 'My Page',
|
|
41
|
+
meta: [
|
|
42
|
+
{ name: 'description', content: 'My page description' },
|
|
43
|
+
{ name: 'description', content: 'Duplicate description' }
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
const expectedOutput = `<meta charset="UTF-8" />
|
|
49
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
50
|
+
<title>My Page</title>
|
|
51
|
+
<meta name="description" content="Duplicate description" />`
|
|
52
|
+
|
|
53
|
+
expect(renderHead(headItems)).toEqual(expectedOutput)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('renderAttrs', () => {
|
|
58
|
+
it('should render boolean attributes correctly', () => {
|
|
59
|
+
const item = { async: true, src: '/script.js' }
|
|
60
|
+
expect(renderAttrs(item)).toEqual('async src="/script.js"')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should filter out invalid attributes', () => {
|
|
64
|
+
const item = {
|
|
65
|
+
innerHTML: '<p>Hello</p>',
|
|
66
|
+
priority: 1,
|
|
67
|
+
tagName: 'script',
|
|
68
|
+
src: '/script.js'
|
|
69
|
+
}
|
|
70
|
+
expect(renderAttrs(item)).toEqual('src="/script.js"')
|
|
71
|
+
})
|
|
72
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const DEFAULT_CHARSET = { charset: 'UTF-8' }
|
|
2
|
-
const DEFAULT_VIEWPORT = {
|
|
2
|
+
const DEFAULT_VIEWPORT = {
|
|
3
|
+
name: 'viewport',
|
|
4
|
+
content: 'width=device-width, initial-scale=1'
|
|
5
|
+
}
|
|
3
6
|
|
|
4
7
|
type TagName = 'meta' | 'link' | 'style' | 'script' | 'noscript'
|
|
5
8
|
|
|
@@ -9,7 +12,7 @@ type BaseItem = {
|
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
type ContentItem = BaseItem & {
|
|
12
|
-
innerHTML
|
|
15
|
+
innerHTML?: string
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
type Tag = (BaseItem | ContentItem) & {
|
|
@@ -155,7 +158,7 @@ function renderHeadTag(item: BaseItem | ContentItem): string {
|
|
|
155
158
|
const attrs = renderAttrs(item)
|
|
156
159
|
return ['meta', 'link'].includes(item.tagName)
|
|
157
160
|
? `<${item.tagName} ${attrs} />`
|
|
158
|
-
: `<${item.tagName}${attrs && ' '}${attrs}>${item.innerHTML}</${
|
|
161
|
+
: `<${item.tagName}${attrs && ' '}${attrs}>${item.innerHTML || ''}</${
|
|
159
162
|
item.tagName
|
|
160
163
|
}>`
|
|
161
164
|
}
|
package/tsconfig.json
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ESNext",
|
|
4
4
|
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Node",
|
|
5
6
|
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
6
8
|
"esModuleInterop": true,
|
|
7
9
|
"forceConsistentCasingInFileNames": true,
|
|
8
10
|
"strict": true,
|
|
9
11
|
"skipLibCheck": true,
|
|
10
12
|
"declaration": true,
|
|
11
|
-
"
|
|
12
|
-
"declarationMap": true
|
|
13
|
+
"sourceMap": true
|
|
13
14
|
},
|
|
14
|
-
"include": ["src/**/*"]
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
15
17
|
}
|