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 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 = { content: 'width=device-width, initial-scale=1' }
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: string;
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 = { content: 'width=device-width, initial-scale=1' };
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.0",
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 = { content: 'width=device-width, initial-scale=1' }
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: string
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
- "emitDeclarationOnly": false,
12
- "declarationMap": true
13
+ "sourceMap": true
13
14
  },
14
- "include": ["src/**/*"]
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules", "dist"]
15
17
  }