tuijs-meta 0.1.2 → 0.1.3
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/LICENSE +21 -21
- package/README.md +130 -130
- package/bin/index.js +40 -40
- package/bin/lib/_logging.js +8 -8
- package/bin/lib/_service.js +123 -123
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +30 -30
- package/src/index.ts +5 -4
- package/src/lib/models.ts +21 -21
- package/src/lib/service.ts +83 -83
- package/tsconfig.json +20 -20
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 TechTB
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 TechTB
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,130 +1,130 @@
|
|
|
1
|
-
# TUIJS-Meta
|
|
2
|
-
*** THIS README IS OUT OF DATE AND WILL BE UPDATED SOON ***
|
|
3
|
-
## A simple and easy utility that updates a web application's meta tags based on a provided set of site data.
|
|
4
|
-
***TUIJS-Meta is built on modules. A bundler is recommended.***
|
|
5
|
-
|
|
6
|
-
***Last Updated 08/05/2024***
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Getting Started
|
|
10
|
-
1. Ensure that you have a set of site data (We will refer to this as 'siteData') created. This can be a JSON file, data in a database, or an Object directly in your JS code. As long as the resulting data is an Object following the format below. For this example we will use a JSON file.
|
|
11
|
-
- The 'siteData' will always consist of a parent Object.
|
|
12
|
-
- The Objects contained within the 'siteData' parent Object should each represent a route path, except for the site wide data which should always be '\*'. The '\*' Object will represent data that is intended to be site wide, and can be empty or non-existent if desired. ***The Object names do not currently matter as long as they are referenced correctly when the 'tuiMeta' function is called. However, once tuijs-meta is integrated into TUI-Router, the naming standard for site data and route data will become important.***
|
|
13
|
-
- Inside the value of each site or route Object, there will be two important keys, 'title' and 'meta'. The 'title' key value will be a string representing the title of the site or page. The 'meta' key value will be an Array of Objects containing meta tag attributes. Each Object can contain as many or as few attributes as needed, but each Object will only ever represent one meta tag.
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"*": {
|
|
18
|
-
"title": "Site Title",
|
|
19
|
-
"meta": [
|
|
20
|
-
{
|
|
21
|
-
"property": "og:title",
|
|
22
|
-
"content": "Title"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"property": "og:description",
|
|
26
|
-
"content": "description"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"property": "og:image",
|
|
30
|
-
"content": "image/path"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"property": "og:url",
|
|
34
|
-
"content": "https://site/path"
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"property": "og:type",
|
|
38
|
-
"content": "website"
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
|
-
"/": {
|
|
43
|
-
"title": "Home Title",
|
|
44
|
-
"meta": [
|
|
45
|
-
{
|
|
46
|
-
"name": "description",
|
|
47
|
-
"content": "Home description"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"name": "keywords",
|
|
51
|
-
"content": "Home keywords"
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
"/about": {
|
|
56
|
-
"title": "About Title",
|
|
57
|
-
"meta": [
|
|
58
|
-
{
|
|
59
|
-
"name": "description",
|
|
60
|
-
"content": "About description"
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"name": "keywords",
|
|
64
|
-
"content": "About keywords"
|
|
65
|
-
}
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"/contact": {
|
|
69
|
-
"title": "Contact Title",
|
|
70
|
-
"meta": [
|
|
71
|
-
{
|
|
72
|
-
"name": "description",
|
|
73
|
-
"content": "Contact description"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"name": "keywords",
|
|
77
|
-
"content": "Contact keywords"
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
2. Import the primary function 'tuiMeta' from 'tuijs-meta'.
|
|
85
|
-
- If you are working with a multi-page app, this should be in the JS file for each page.
|
|
86
|
-
- If you you are working with a single-page app, this should be done where ever you route logic is.
|
|
87
|
-
- ***The 'tuiMeta' function is exported as default.***
|
|
88
|
-
|
|
89
|
-
```js
|
|
90
|
-
import tuiMeta from 'tuijs-meta';
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
3. Execute the 'tuiMeta function' using the desired site or route data from the siteData source. ***It is important to note that you must use one of the seconds Objects as the parameter and NOT the full site data Object.***
|
|
94
|
-
- In the following example, the site data is directly in the JS code and is provided as a parameter in the 'tuiMeta' function. In this case, the page head will populate with the HTML tags listed below.
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
const siteData = {
|
|
98
|
-
'*': {
|
|
99
|
-
title: 'Site Title',
|
|
100
|
-
meta: [
|
|
101
|
-
{
|
|
102
|
-
name: 'description',
|
|
103
|
-
content: 'Site description'
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
name: 'keywords',
|
|
107
|
-
content: 'Site keywords'
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
tuiMeta(siteData['*']);
|
|
113
|
-
```
|
|
114
|
-
```html
|
|
115
|
-
<title>Site Title</title>
|
|
116
|
-
<meta name="description" content="Site description">
|
|
117
|
-
<meta name="keywords" content="Site keywords">
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
4. When the 'tuiMeta' function is called it will check the head for other existing meta tags that have key/value pairs that match exactly. If it finds any, they will be deleted allowing the new site or route meta data to be added. ***It should be noted that 'content' attributes are completely ignored during this check. So if a content key/value pair match, nothing will be deleted.***
|
|
121
|
-
|
|
122
|
-
## How It Works
|
|
123
|
-
1. When the 'tuiMeta' function is called, the site data provided is first checked to ensure that it is an Object.
|
|
124
|
-
2. The function then validates that the 'title' key exists.
|
|
125
|
-
- If the 'title' key exists, the function attempts to update the document title with the 'title' key value.
|
|
126
|
-
- If the 'title' key DOES NOT exists, no error is generated and the function just moves on.
|
|
127
|
-
2. The function then validates that the 'meta' key exists.
|
|
128
|
-
- If the 'meta' key exists, the function then validates that the value of the 'meta' key is an Array, throwing an error if it is not.
|
|
129
|
-
-If the 'meta' key value is an Array, then the function attempts to update the document meta tags with the 'meta' key Array data. As as reminder this Array consists of Objects, each representing a single meta tag. Within each Object, there is a set as many or as few key/value pairs as needed, each representing a single meta tag attribute and its value.
|
|
130
|
-
- If the 'meta' key DOES NOT exists, no error is generated and the function just moves on.
|
|
1
|
+
# TUIJS-Meta
|
|
2
|
+
*** THIS README IS OUT OF DATE AND WILL BE UPDATED SOON ***
|
|
3
|
+
## A simple and easy utility that updates a web application's meta tags based on a provided set of site data.
|
|
4
|
+
***TUIJS-Meta is built on modules. A bundler is recommended.***
|
|
5
|
+
|
|
6
|
+
***Last Updated 08/05/2024***
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
1. Ensure that you have a set of site data (We will refer to this as 'siteData') created. This can be a JSON file, data in a database, or an Object directly in your JS code. As long as the resulting data is an Object following the format below. For this example we will use a JSON file.
|
|
11
|
+
- The 'siteData' will always consist of a parent Object.
|
|
12
|
+
- The Objects contained within the 'siteData' parent Object should each represent a route path, except for the site wide data which should always be '\*'. The '\*' Object will represent data that is intended to be site wide, and can be empty or non-existent if desired. ***The Object names do not currently matter as long as they are referenced correctly when the 'tuiMeta' function is called. However, once tuijs-meta is integrated into TUI-Router, the naming standard for site data and route data will become important.***
|
|
13
|
+
- Inside the value of each site or route Object, there will be two important keys, 'title' and 'meta'. The 'title' key value will be a string representing the title of the site or page. The 'meta' key value will be an Array of Objects containing meta tag attributes. Each Object can contain as many or as few attributes as needed, but each Object will only ever represent one meta tag.
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"*": {
|
|
18
|
+
"title": "Site Title",
|
|
19
|
+
"meta": [
|
|
20
|
+
{
|
|
21
|
+
"property": "og:title",
|
|
22
|
+
"content": "Title"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"property": "og:description",
|
|
26
|
+
"content": "description"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"property": "og:image",
|
|
30
|
+
"content": "image/path"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"property": "og:url",
|
|
34
|
+
"content": "https://site/path"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"property": "og:type",
|
|
38
|
+
"content": "website"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"/": {
|
|
43
|
+
"title": "Home Title",
|
|
44
|
+
"meta": [
|
|
45
|
+
{
|
|
46
|
+
"name": "description",
|
|
47
|
+
"content": "Home description"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "keywords",
|
|
51
|
+
"content": "Home keywords"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"/about": {
|
|
56
|
+
"title": "About Title",
|
|
57
|
+
"meta": [
|
|
58
|
+
{
|
|
59
|
+
"name": "description",
|
|
60
|
+
"content": "About description"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "keywords",
|
|
64
|
+
"content": "About keywords"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"/contact": {
|
|
69
|
+
"title": "Contact Title",
|
|
70
|
+
"meta": [
|
|
71
|
+
{
|
|
72
|
+
"name": "description",
|
|
73
|
+
"content": "Contact description"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "keywords",
|
|
77
|
+
"content": "Contact keywords"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Import the primary function 'tuiMeta' from 'tuijs-meta'.
|
|
85
|
+
- If you are working with a multi-page app, this should be in the JS file for each page.
|
|
86
|
+
- If you you are working with a single-page app, this should be done where ever you route logic is.
|
|
87
|
+
- ***The 'tuiMeta' function is exported as default.***
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
import tuiMeta from 'tuijs-meta';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
3. Execute the 'tuiMeta function' using the desired site or route data from the siteData source. ***It is important to note that you must use one of the seconds Objects as the parameter and NOT the full site data Object.***
|
|
94
|
+
- In the following example, the site data is directly in the JS code and is provided as a parameter in the 'tuiMeta' function. In this case, the page head will populate with the HTML tags listed below.
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
const siteData = {
|
|
98
|
+
'*': {
|
|
99
|
+
title: 'Site Title',
|
|
100
|
+
meta: [
|
|
101
|
+
{
|
|
102
|
+
name: 'description',
|
|
103
|
+
content: 'Site description'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'keywords',
|
|
107
|
+
content: 'Site keywords'
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
tuiMeta(siteData['*']);
|
|
113
|
+
```
|
|
114
|
+
```html
|
|
115
|
+
<title>Site Title</title>
|
|
116
|
+
<meta name="description" content="Site description">
|
|
117
|
+
<meta name="keywords" content="Site keywords">
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
4. When the 'tuiMeta' function is called it will check the head for other existing meta tags that have key/value pairs that match exactly. If it finds any, they will be deleted allowing the new site or route meta data to be added. ***It should be noted that 'content' attributes are completely ignored during this check. So if a content key/value pair match, nothing will be deleted.***
|
|
121
|
+
|
|
122
|
+
## How It Works
|
|
123
|
+
1. When the 'tuiMeta' function is called, the site data provided is first checked to ensure that it is an Object.
|
|
124
|
+
2. The function then validates that the 'title' key exists.
|
|
125
|
+
- If the 'title' key exists, the function attempts to update the document title with the 'title' key value.
|
|
126
|
+
- If the 'title' key DOES NOT exists, no error is generated and the function just moves on.
|
|
127
|
+
2. The function then validates that the 'meta' key exists.
|
|
128
|
+
- If the 'meta' key exists, the function then validates that the value of the 'meta' key is an Array, throwing an error if it is not.
|
|
129
|
+
-If the 'meta' key value is an Array, then the function attempts to update the document meta tags with the 'meta' key Array data. As as reminder this Array consists of Objects, each representing a single meta tag. Within each Object, there is a set as many or as few key/value pairs as needed, each representing a single meta tag attribute and its value.
|
|
130
|
+
- If the 'meta' key DOES NOT exists, no error is generated and the function just moves on.
|
package/bin/index.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
#! /usr/bin/env node
|
|
2
|
-
import { checkUrl } from 'tuijs-util';
|
|
3
|
-
import { consoleLog } from './lib/_logging.js';
|
|
4
|
-
import createSiteMap from './lib/siteMap.js';
|
|
5
|
-
|
|
6
|
-
(async () => {
|
|
7
|
-
try {
|
|
8
|
-
consoleLog({ type: 'info', message: `\n\n--------------------------\n` });
|
|
9
|
-
consoleLog({ type: 'info', message: `Attempting to generate site map...\n` });
|
|
10
|
-
const arg = process.argv.slice(2);
|
|
11
|
-
const data = {
|
|
12
|
-
configFile: '',
|
|
13
|
-
inputFile: '',
|
|
14
|
-
outputFile: 'sitemap.xml'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (!arg[0]) {
|
|
18
|
-
throw new Error(`No arguments provided.`);
|
|
19
|
-
}
|
|
20
|
-
if (!arg[0].toLowerCase().endsWith('.json')) {
|
|
21
|
-
throw new Error(`The first argument must be a valid config JSON file.`);
|
|
22
|
-
}
|
|
23
|
-
data.configFile = arg[0];
|
|
24
|
-
|
|
25
|
-
if (!arg[1]) {
|
|
26
|
-
throw new Error(`No site data input file provided.`);
|
|
27
|
-
}
|
|
28
|
-
data.inputFile = arg[1];
|
|
29
|
-
|
|
30
|
-
if (!arg[2]) {
|
|
31
|
-
consoleLog({ type: 'warning', message: `No output file provided. Using the default 'sitemap.xml'.` });
|
|
32
|
-
}
|
|
33
|
-
data.outputFile = arg[2] || data.outputFile;
|
|
34
|
-
await createSiteMap(data.configFile, data.inputFile, data.outputFile);
|
|
35
|
-
return;
|
|
36
|
-
} catch (er) {
|
|
37
|
-
consoleLog({ type: 'error', message: `Error generating site map.` })
|
|
38
|
-
consoleLog({ type: 'error', message: er.toString() });
|
|
39
|
-
}
|
|
40
|
-
})();
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
import { checkUrl } from 'tuijs-util';
|
|
3
|
+
import { consoleLog } from './lib/_logging.js';
|
|
4
|
+
import createSiteMap from './lib/siteMap.js';
|
|
5
|
+
|
|
6
|
+
(async () => {
|
|
7
|
+
try {
|
|
8
|
+
consoleLog({ type: 'info', message: `\n\n--------------------------\n` });
|
|
9
|
+
consoleLog({ type: 'info', message: `Attempting to generate site map...\n` });
|
|
10
|
+
const arg = process.argv.slice(2);
|
|
11
|
+
const data = {
|
|
12
|
+
configFile: '',
|
|
13
|
+
inputFile: '',
|
|
14
|
+
outputFile: 'sitemap.xml'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!arg[0]) {
|
|
18
|
+
throw new Error(`No arguments provided.`);
|
|
19
|
+
}
|
|
20
|
+
if (!arg[0].toLowerCase().endsWith('.json')) {
|
|
21
|
+
throw new Error(`The first argument must be a valid config JSON file.`);
|
|
22
|
+
}
|
|
23
|
+
data.configFile = arg[0];
|
|
24
|
+
|
|
25
|
+
if (!arg[1]) {
|
|
26
|
+
throw new Error(`No site data input file provided.`);
|
|
27
|
+
}
|
|
28
|
+
data.inputFile = arg[1];
|
|
29
|
+
|
|
30
|
+
if (!arg[2]) {
|
|
31
|
+
consoleLog({ type: 'warning', message: `No output file provided. Using the default 'sitemap.xml'.` });
|
|
32
|
+
}
|
|
33
|
+
data.outputFile = arg[2] || data.outputFile;
|
|
34
|
+
await createSiteMap(data.configFile, data.inputFile, data.outputFile);
|
|
35
|
+
return;
|
|
36
|
+
} catch (er) {
|
|
37
|
+
consoleLog({ type: 'error', message: `Error generating site map.` })
|
|
38
|
+
consoleLog({ type: 'error', message: er.toString() });
|
|
39
|
+
}
|
|
40
|
+
})();
|
package/bin/lib/_logging.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createSmartLogInstance } from 'smart-log-node';
|
|
2
|
-
|
|
3
|
-
const logger = createSmartLogInstance();
|
|
4
|
-
const { consoleLog } = logger;
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
consoleLog
|
|
8
|
-
}
|
|
1
|
+
import { createSmartLogInstance } from 'smart-log-node';
|
|
2
|
+
|
|
3
|
+
const logger = createSmartLogInstance();
|
|
4
|
+
const { consoleLog } = logger;
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
consoleLog
|
|
8
|
+
}
|
package/bin/lib/_service.js
CHANGED
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { pathToFileURL } from 'url';
|
|
4
|
-
|
|
5
|
-
import { JSDOM } from 'jsdom';
|
|
6
|
-
import { checkIsArray, checkIsObject } from 'tuijs-util';
|
|
7
|
-
|
|
8
|
-
import { consoleLog } from './_logging.js';
|
|
9
|
-
|
|
10
|
-
async function createSiteMap(configFile, inputFile, outputFile) {
|
|
11
|
-
try {
|
|
12
|
-
const data = fs.readFileSync(inputFile, 'utf-8');
|
|
13
|
-
let routeDataArray = [];
|
|
14
|
-
|
|
15
|
-
switch (inputFile.toLowerCase().split('.').pop()) {
|
|
16
|
-
case 'json':
|
|
17
|
-
routeDataArray = JSON.parse(data);
|
|
18
|
-
break;
|
|
19
|
-
case 'js':
|
|
20
|
-
const fileURL = pathToFileURL(path.resolve(inputFile));
|
|
21
|
-
const module = await import(fileURL);
|
|
22
|
-
routeDataArray = module.default || module;
|
|
23
|
-
break;
|
|
24
|
-
default:
|
|
25
|
-
throw new Error(`The provided inputFile is not a .json or .js file.`);
|
|
26
|
-
}
|
|
27
|
-
if (!checkIsArray(routeDataArray)) {
|
|
28
|
-
throw new Error(`The provided site data is not a valid JavaScript Array.`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const dom = new JSDOM(elmSite(), { contentType: "text/xml" });
|
|
32
|
-
const document = dom.window.document;
|
|
33
|
-
|
|
34
|
-
for (let i = 0; i < routeDataArray.length; i++) {
|
|
35
|
-
const routeObject = routeDataArray[i];
|
|
36
|
-
if (!checkIsObject(routeObject)) {
|
|
37
|
-
consoleLog({ type: 'warning', message: `The provided site data array contains a non-object entry at index ${i}. Skipping this entry.` });
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const routeObjectMapData = routeObject['map'];
|
|
42
|
-
if (!routeObjectMapData) {
|
|
43
|
-
consoleLog({ type: 'warning', message: `The provided site data object at index ${i} is missing the required 'map' property.` });
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const routeObjectRoute = routeObject['route'];
|
|
48
|
-
if (!routeObjectRoute) {
|
|
49
|
-
consoleLog({ type: 'warning', message: `The provided site data object at index ${i} is missing the required 'route' property.` });
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (routeObjectRoute === '*') {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const routeElement = addRouteToMap(rootUrl, routeObjectRoute, routeObjectMapData, document);
|
|
57
|
-
document.querySelector("urlset").appendChild(routeElement);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const siteMapSerialized = new dom.window.XMLSerializer().serializeToString(document);
|
|
61
|
-
const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
62
|
-
const siteMapFinal = xmlDeclaration + siteMapSerialized;
|
|
63
|
-
createFile(outputFile, siteMapFinal);
|
|
64
|
-
} catch (er) {
|
|
65
|
-
throw new Error(er);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function elmSite() {
|
|
70
|
-
return `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function addRouteToMap(root, route, data, document) {
|
|
74
|
-
try {
|
|
75
|
-
const elmUrl = document.createElementNS(null, 'url');
|
|
76
|
-
if (!elmUrl) {
|
|
77
|
-
throw new Error(`Could not create 'url' element.`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const elmLoc = document.createElementNS(null, 'loc');
|
|
81
|
-
if (elmLoc) {
|
|
82
|
-
elmLoc.textContent = `${root}${route.startsWith('/') ? '' : '/'}${route}`;
|
|
83
|
-
elmUrl.appendChild(elmLoc);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
for (const [key, value] of Object.entries(data)) {
|
|
87
|
-
const elmUrlChild = document.createElementNS(null, `${key}`);
|
|
88
|
-
if (elmUrlChild) {
|
|
89
|
-
elmUrlChild.textContent = value;
|
|
90
|
-
elmUrl.appendChild(elmUrlChild);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const elmLastMod = elmUrl.querySelector('lastmod');
|
|
95
|
-
if (elmLastMod) {
|
|
96
|
-
const date = new Date(elmLastMod.textContent || '');
|
|
97
|
-
elmLastMod.textContent = date.toISOString().split('T')[0];
|
|
98
|
-
}
|
|
99
|
-
elmUrl.appendChild(elmLastMod);
|
|
100
|
-
|
|
101
|
-
if (elmUrl.hasAttribute('xmlns')) {
|
|
102
|
-
elmUrl.removeAttribute('xmlns');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return elmUrl;
|
|
106
|
-
} catch (er) {
|
|
107
|
-
throw new Error(er);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function createFile(filePath, fileTemplate) {
|
|
112
|
-
try {
|
|
113
|
-
fs.writeFileSync(filePath, fileTemplate);
|
|
114
|
-
consoleLog({ type: 'info', message: `File '${filePath}' created.` });
|
|
115
|
-
return;
|
|
116
|
-
} catch (er) {
|
|
117
|
-
throw new Error(er);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export default {
|
|
122
|
-
createSiteMap
|
|
123
|
-
}
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
|
|
5
|
+
import { JSDOM } from 'jsdom';
|
|
6
|
+
import { checkIsArray, checkIsObject } from 'tuijs-util';
|
|
7
|
+
|
|
8
|
+
import { consoleLog } from './_logging.js';
|
|
9
|
+
|
|
10
|
+
async function createSiteMap(configFile, inputFile, outputFile) {
|
|
11
|
+
try {
|
|
12
|
+
const data = fs.readFileSync(inputFile, 'utf-8');
|
|
13
|
+
let routeDataArray = [];
|
|
14
|
+
|
|
15
|
+
switch (inputFile.toLowerCase().split('.').pop()) {
|
|
16
|
+
case 'json':
|
|
17
|
+
routeDataArray = JSON.parse(data);
|
|
18
|
+
break;
|
|
19
|
+
case 'js':
|
|
20
|
+
const fileURL = pathToFileURL(path.resolve(inputFile));
|
|
21
|
+
const module = await import(fileURL);
|
|
22
|
+
routeDataArray = module.default || module;
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`The provided inputFile is not a .json or .js file.`);
|
|
26
|
+
}
|
|
27
|
+
if (!checkIsArray(routeDataArray)) {
|
|
28
|
+
throw new Error(`The provided site data is not a valid JavaScript Array.`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const dom = new JSDOM(elmSite(), { contentType: "text/xml" });
|
|
32
|
+
const document = dom.window.document;
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < routeDataArray.length; i++) {
|
|
35
|
+
const routeObject = routeDataArray[i];
|
|
36
|
+
if (!checkIsObject(routeObject)) {
|
|
37
|
+
consoleLog({ type: 'warning', message: `The provided site data array contains a non-object entry at index ${i}. Skipping this entry.` });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const routeObjectMapData = routeObject['map'];
|
|
42
|
+
if (!routeObjectMapData) {
|
|
43
|
+
consoleLog({ type: 'warning', message: `The provided site data object at index ${i} is missing the required 'map' property.` });
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const routeObjectRoute = routeObject['route'];
|
|
48
|
+
if (!routeObjectRoute) {
|
|
49
|
+
consoleLog({ type: 'warning', message: `The provided site data object at index ${i} is missing the required 'route' property.` });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (routeObjectRoute === '*') {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const routeElement = addRouteToMap(rootUrl, routeObjectRoute, routeObjectMapData, document);
|
|
57
|
+
document.querySelector("urlset").appendChild(routeElement);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const siteMapSerialized = new dom.window.XMLSerializer().serializeToString(document);
|
|
61
|
+
const xmlDeclaration = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
62
|
+
const siteMapFinal = xmlDeclaration + siteMapSerialized;
|
|
63
|
+
createFile(outputFile, siteMapFinal);
|
|
64
|
+
} catch (er) {
|
|
65
|
+
throw new Error(er);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function elmSite() {
|
|
70
|
+
return `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function addRouteToMap(root, route, data, document) {
|
|
74
|
+
try {
|
|
75
|
+
const elmUrl = document.createElementNS(null, 'url');
|
|
76
|
+
if (!elmUrl) {
|
|
77
|
+
throw new Error(`Could not create 'url' element.`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const elmLoc = document.createElementNS(null, 'loc');
|
|
81
|
+
if (elmLoc) {
|
|
82
|
+
elmLoc.textContent = `${root}${route.startsWith('/') ? '' : '/'}${route}`;
|
|
83
|
+
elmUrl.appendChild(elmLoc);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const [key, value] of Object.entries(data)) {
|
|
87
|
+
const elmUrlChild = document.createElementNS(null, `${key}`);
|
|
88
|
+
if (elmUrlChild) {
|
|
89
|
+
elmUrlChild.textContent = value;
|
|
90
|
+
elmUrl.appendChild(elmUrlChild);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const elmLastMod = elmUrl.querySelector('lastmod');
|
|
95
|
+
if (elmLastMod) {
|
|
96
|
+
const date = new Date(elmLastMod.textContent || '');
|
|
97
|
+
elmLastMod.textContent = date.toISOString().split('T')[0];
|
|
98
|
+
}
|
|
99
|
+
elmUrl.appendChild(elmLastMod);
|
|
100
|
+
|
|
101
|
+
if (elmUrl.hasAttribute('xmlns')) {
|
|
102
|
+
elmUrl.removeAttribute('xmlns');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return elmUrl;
|
|
106
|
+
} catch (er) {
|
|
107
|
+
throw new Error(er);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function createFile(filePath, fileTemplate) {
|
|
112
|
+
try {
|
|
113
|
+
fs.writeFileSync(filePath, fileTemplate);
|
|
114
|
+
consoleLog({ type: 'info', message: `File '${filePath}' created.` });
|
|
115
|
+
return;
|
|
116
|
+
} catch (er) {
|
|
117
|
+
throw new Error(er);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default {
|
|
122
|
+
createSiteMap
|
|
123
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createMetaInstance
|
|
1
|
+
export { createMetaInstance } from './lib/service.js';
|
|
2
|
+
export { createMetaInstance as tuiMeta } from "./lib/service.js";
|
|
2
3
|
export type { MetaRoute, MetaTag, MetaTypeKey } from "./lib/models.js";
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createMetaInstance
|
|
1
|
+
export { createMetaInstance } from './lib/service.js';
|
|
2
|
+
export { createMetaInstance as tuiMeta } from "./lib/service.js";
|
|
2
3
|
// TO DO - Update readme
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,kBAAkB,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGjE,wBAAwB"}
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "tuijs-meta",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A JavaScript utility that manipulates meta data tags based on provided data.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
10
|
-
"import": "./dist/index.js",
|
|
11
|
-
"require": "./dist/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"author": "TechTB",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"repository": "github:TechTB-OpenSource/tuijs-meta",
|
|
17
|
-
"type": "module",
|
|
18
|
-
"scripts": {
|
|
19
|
-
"clean": "rimraf dist",
|
|
20
|
-
"build": "npm run clean && tsc",
|
|
21
|
-
"sitemap": "node ./bin/index.js"
|
|
22
|
-
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"tuijs-util": "^1.5.1"
|
|
25
|
-
},
|
|
26
|
-
"devDependencies": {
|
|
27
|
-
"rimraf": "^6.
|
|
28
|
-
"typescript": "^5.9.3"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "tuijs-meta",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "A JavaScript utility that manipulates meta data tags based on provided data.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"author": "TechTB",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": "github:TechTB-OpenSource/tuijs-meta",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clean": "rimraf dist",
|
|
20
|
+
"build": "npm run clean && tsc",
|
|
21
|
+
"sitemap": "node ./bin/index.js"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"tuijs-util": "^1.5.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"rimraf": "^6.1.3",
|
|
28
|
+
"typescript": "^5.9.3"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { createMetaInstance
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export { createMetaInstance } from './lib/service.js';
|
|
2
|
+
export { createMetaInstance as tuiMeta } from "./lib/service.js";
|
|
3
|
+
export type { MetaRoute, MetaTag, MetaTypeKey } from "./lib/models.js";
|
|
4
|
+
|
|
5
|
+
// TO DO - Update readme
|
package/src/lib/models.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export type MetaTypeKey = 'name' | 'property' | 'itemprop';
|
|
2
|
-
|
|
3
|
-
export type MetaTag = {
|
|
4
|
-
[K in MetaTypeKey]?: string;
|
|
5
|
-
} & {
|
|
6
|
-
content: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export interface MetaRoute {
|
|
10
|
-
route: string;
|
|
11
|
-
title?: string;
|
|
12
|
-
meta?: Array<MetaTag>;
|
|
13
|
-
map?: Map;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface Map {
|
|
17
|
-
loc: string;
|
|
18
|
-
lastmod?: string;
|
|
19
|
-
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
20
|
-
priority?: number;
|
|
21
|
-
}
|
|
1
|
+
export type MetaTypeKey = 'name' | 'property' | 'itemprop';
|
|
2
|
+
|
|
3
|
+
export type MetaTag = {
|
|
4
|
+
[K in MetaTypeKey]?: string;
|
|
5
|
+
} & {
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface MetaRoute {
|
|
10
|
+
route: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
meta?: Array<MetaTag>;
|
|
13
|
+
map?: Map;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Map {
|
|
17
|
+
loc: string;
|
|
18
|
+
lastmod?: string;
|
|
19
|
+
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
20
|
+
priority?: number;
|
|
21
|
+
}
|
package/src/lib/service.ts
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import type { MetaRoute, MetaTag } from './models.js';
|
|
2
|
-
|
|
3
|
-
export function createMetaInstance() {
|
|
4
|
-
const metaData: MetaRoute[] = [];
|
|
5
|
-
|
|
6
|
-
function setMetaData(metaRoutes: MetaRoute[]) {
|
|
7
|
-
metaData.length = 0;
|
|
8
|
-
metaData.push(...metaRoutes);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function metaUpdate(metaData: MetaTag[]) {
|
|
12
|
-
for (let i = 0; i < metaData.length; i++) {
|
|
13
|
-
metaUpdateTag(metaData[i]);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function metaRouteUpdate(route: string) {
|
|
18
|
-
let globalRouteMeta, specifiedRouteMeta: MetaRoute | undefined;
|
|
19
|
-
for (let i = 0; i < metaData.length; i++) {
|
|
20
|
-
const item = metaData[i];
|
|
21
|
-
if (item.route === '*') globalRouteMeta = item;
|
|
22
|
-
if (item.route === route) specifiedRouteMeta = item;
|
|
23
|
-
if (globalRouteMeta && specifiedRouteMeta) break;
|
|
24
|
-
}
|
|
25
|
-
if (!globalRouteMeta && !specifiedRouteMeta) {
|
|
26
|
-
console.error(`tuijs-meta: No meta data found for route "${route}", and no global meta route defined.`);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (globalRouteMeta) {
|
|
30
|
-
if (globalRouteMeta.meta) {
|
|
31
|
-
const globalMeta: MetaTag[] = globalRouteMeta.meta;
|
|
32
|
-
for (let i = 0; i < globalMeta.length; i++) {
|
|
33
|
-
metaUpdateTag(globalMeta[i]);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (!specifiedRouteMeta) {
|
|
38
|
-
document.title = globalRouteMeta?.title || 'Unknown Page';
|
|
39
|
-
console.warn(`tuijs-meta: No specific meta data found for route "${route}".`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (specifiedRouteMeta.title) {
|
|
43
|
-
document.title = specifiedRouteMeta.title;
|
|
44
|
-
} else {
|
|
45
|
-
document.title = globalRouteMeta?.title || 'Unknown Page';
|
|
46
|
-
}
|
|
47
|
-
if (specifiedRouteMeta.meta) {
|
|
48
|
-
const dataMeta: MetaTag[] = specifiedRouteMeta.meta;
|
|
49
|
-
for (let i = 0; i < dataMeta.length; i++) {
|
|
50
|
-
metaUpdateTag(dataMeta[i]);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function metaUpdateTag(newMetaTag: MetaTag) {
|
|
57
|
-
const existingMetaTagList = Array.from(document.getElementsByTagName('meta'));
|
|
58
|
-
|
|
59
|
-
// Find the meta type key and value dynamically
|
|
60
|
-
const metaEntries = Object.entries(newMetaTag).filter(([key]) => key !== 'content');
|
|
61
|
-
const [typeKey, typeValue] = metaEntries[0];
|
|
62
|
-
|
|
63
|
-
// Remove existing meta tags that match the typeKey and typeValue
|
|
64
|
-
existingMetaTagList.forEach(existingMetaTag => {
|
|
65
|
-
if (existingMetaTag.getAttribute(typeKey) === typeValue) {
|
|
66
|
-
existingMetaTag.remove();
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Create and append the new meta tag
|
|
71
|
-
const elmMeta = document.createElement('meta');
|
|
72
|
-
elmMeta.setAttribute(typeKey, typeValue);
|
|
73
|
-
elmMeta.setAttribute('content', newMetaTag.content);
|
|
74
|
-
document.head.appendChild(elmMeta);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
setMetaData,
|
|
80
|
-
metaUpdate,
|
|
81
|
-
metaRouteUpdate
|
|
82
|
-
}
|
|
83
|
-
}
|
|
1
|
+
import type { MetaRoute, MetaTag } from './models.js';
|
|
2
|
+
|
|
3
|
+
export function createMetaInstance() {
|
|
4
|
+
const metaData: MetaRoute[] = [];
|
|
5
|
+
|
|
6
|
+
function setMetaData(metaRoutes: MetaRoute[]) {
|
|
7
|
+
metaData.length = 0;
|
|
8
|
+
metaData.push(...metaRoutes);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function metaUpdate(metaData: MetaTag[]) {
|
|
12
|
+
for (let i = 0; i < metaData.length; i++) {
|
|
13
|
+
metaUpdateTag(metaData[i]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function metaRouteUpdate(route: string) {
|
|
18
|
+
let globalRouteMeta, specifiedRouteMeta: MetaRoute | undefined;
|
|
19
|
+
for (let i = 0; i < metaData.length; i++) {
|
|
20
|
+
const item = metaData[i];
|
|
21
|
+
if (item.route === '*') globalRouteMeta = item;
|
|
22
|
+
if (item.route === route) specifiedRouteMeta = item;
|
|
23
|
+
if (globalRouteMeta && specifiedRouteMeta) break;
|
|
24
|
+
}
|
|
25
|
+
if (!globalRouteMeta && !specifiedRouteMeta) {
|
|
26
|
+
console.error(`tuijs-meta: No meta data found for route "${route}", and no global meta route defined.`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (globalRouteMeta) {
|
|
30
|
+
if (globalRouteMeta.meta) {
|
|
31
|
+
const globalMeta: MetaTag[] = globalRouteMeta.meta;
|
|
32
|
+
for (let i = 0; i < globalMeta.length; i++) {
|
|
33
|
+
metaUpdateTag(globalMeta[i]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!specifiedRouteMeta) {
|
|
38
|
+
document.title = globalRouteMeta?.title || 'Unknown Page';
|
|
39
|
+
console.warn(`tuijs-meta: No specific meta data found for route "${route}".`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (specifiedRouteMeta.title) {
|
|
43
|
+
document.title = specifiedRouteMeta.title;
|
|
44
|
+
} else {
|
|
45
|
+
document.title = globalRouteMeta?.title || 'Unknown Page';
|
|
46
|
+
}
|
|
47
|
+
if (specifiedRouteMeta.meta) {
|
|
48
|
+
const dataMeta: MetaTag[] = specifiedRouteMeta.meta;
|
|
49
|
+
for (let i = 0; i < dataMeta.length; i++) {
|
|
50
|
+
metaUpdateTag(dataMeta[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function metaUpdateTag(newMetaTag: MetaTag) {
|
|
57
|
+
const existingMetaTagList = Array.from(document.getElementsByTagName('meta'));
|
|
58
|
+
|
|
59
|
+
// Find the meta type key and value dynamically
|
|
60
|
+
const metaEntries = Object.entries(newMetaTag).filter(([key]) => key !== 'content');
|
|
61
|
+
const [typeKey, typeValue] = metaEntries[0];
|
|
62
|
+
|
|
63
|
+
// Remove existing meta tags that match the typeKey and typeValue
|
|
64
|
+
existingMetaTagList.forEach(existingMetaTag => {
|
|
65
|
+
if (existingMetaTag.getAttribute(typeKey) === typeValue) {
|
|
66
|
+
existingMetaTag.remove();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Create and append the new meta tag
|
|
71
|
+
const elmMeta = document.createElement('meta');
|
|
72
|
+
elmMeta.setAttribute(typeKey, typeValue);
|
|
73
|
+
elmMeta.setAttribute('content', newMetaTag.content);
|
|
74
|
+
document.head.appendChild(elmMeta);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
setMetaData,
|
|
80
|
+
metaUpdate,
|
|
81
|
+
metaRouteUpdate
|
|
82
|
+
}
|
|
83
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"rootDir": "./src",
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
"module": "ES2022",
|
|
6
|
-
"target": "ES2020",
|
|
7
|
-
"lib": ["ES2020", "DOM"],
|
|
8
|
-
"moduleResolution": "node",
|
|
9
|
-
"declaration": true,
|
|
10
|
-
"declarationMap": true,
|
|
11
|
-
"sourceMap": true,
|
|
12
|
-
"strict": true,
|
|
13
|
-
"esModuleInterop": true,
|
|
14
|
-
"allowSyntheticDefaultImports": true,
|
|
15
|
-
"forceConsistentCasingInFileNames": true,
|
|
16
|
-
"skipLibCheck": true
|
|
17
|
-
},
|
|
18
|
-
"include": ["src/**/*"],
|
|
19
|
-
"exclude": ["node_modules", "dist"]
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "./src",
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"module": "ES2022",
|
|
6
|
+
"target": "ES2020",
|
|
7
|
+
"lib": ["ES2020", "DOM"],
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"allowSyntheticDefaultImports": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"skipLibCheck": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|