adstxt-validator 1.2.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 -0
- package/README.md +806 -0
- package/dist/index.d.ts +238 -0
- package/dist/index.js +1273 -0
- package/dist/locales/en/validation.json +89 -0
- package/dist/locales/ja/validation.json +89 -0
- package/dist/messages.d.ts +263 -0
- package/dist/messages.js +189 -0
- package/package.json +55 -0
- package/src/locales/en/validation.json +89 -0
- package/src/locales/ja/validation.json +89 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"validation_errors": {
|
|
3
|
+
"missingFields": {
|
|
4
|
+
"message": "Missing required fields",
|
|
5
|
+
"description": "Ads.txt entries require three mandatory fields: domain, account ID, and relationship",
|
|
6
|
+
"helpUrl": "/help/#missing-fields"
|
|
7
|
+
},
|
|
8
|
+
"invalidFormat": {
|
|
9
|
+
"message": "Invalid format",
|
|
10
|
+
"description": "The ads.txt entry format is incorrect. Please use comma-separated format",
|
|
11
|
+
"helpUrl": "/help/#invalid-format"
|
|
12
|
+
},
|
|
13
|
+
"invalidRelationship": {
|
|
14
|
+
"message": "Invalid relationship",
|
|
15
|
+
"description": "Relationship must be either 'DIRECT' or 'RESELLER'",
|
|
16
|
+
"helpUrl": "/help/#invalid-relationship"
|
|
17
|
+
},
|
|
18
|
+
"invalidDomain": {
|
|
19
|
+
"message": "Invalid domain",
|
|
20
|
+
"description": "The specified domain '{{domain}}' is not a valid domain format",
|
|
21
|
+
"helpUrl": "/help/#invalid-domain"
|
|
22
|
+
},
|
|
23
|
+
"emptyAccountId": {
|
|
24
|
+
"message": "Account ID is empty",
|
|
25
|
+
"description": "Account ID is a required field",
|
|
26
|
+
"helpUrl": "/help/#empty-account-id"
|
|
27
|
+
},
|
|
28
|
+
"emptyFile": {
|
|
29
|
+
"message": "File is empty",
|
|
30
|
+
"description": "The ads.txt file contains no content",
|
|
31
|
+
"helpUrl": "/help/#empty-file"
|
|
32
|
+
},
|
|
33
|
+
"invalidCharacters": {
|
|
34
|
+
"message": "Contains invalid characters",
|
|
35
|
+
"description": "The ads.txt file contains non-printable or control characters",
|
|
36
|
+
"helpUrl": "/help/#invalid-characters"
|
|
37
|
+
},
|
|
38
|
+
"noSellersJson": {
|
|
39
|
+
"message": "sellers.json file not found for {{domain}}",
|
|
40
|
+
"description": "The specified advertising system does not have a sellers.json file",
|
|
41
|
+
"helpUrl": "/help/#no-sellers-json"
|
|
42
|
+
},
|
|
43
|
+
"directAccountIdNotInSellersJson": {
|
|
44
|
+
"message": "DIRECT entry account ID '{{accountId}}' not found in sellers.json",
|
|
45
|
+
"description": "DIRECT relationship entries must have their account ID registered in the corresponding sellers.json file",
|
|
46
|
+
"helpUrl": "/help/#direct-account-id-not-in-sellers-json"
|
|
47
|
+
},
|
|
48
|
+
"resellerAccountIdNotInSellersJson": {
|
|
49
|
+
"message": "RESELLER entry account ID '{{accountId}}' not found in sellers.json",
|
|
50
|
+
"description": "RESELLER relationship entries must have their account ID registered in the corresponding sellers.json file",
|
|
51
|
+
"helpUrl": "/help/#reseller-account-id-not-in-sellers-json"
|
|
52
|
+
},
|
|
53
|
+
"domainMismatch": {
|
|
54
|
+
"message": "Domain mismatch: {{sellerDomain}}",
|
|
55
|
+
"description": "The domain in sellers.json does not match the OWNERDOMAIN/MANAGERDOMAIN in ads.txt",
|
|
56
|
+
"helpUrl": "/help/#domain-mismatch"
|
|
57
|
+
},
|
|
58
|
+
"directNotPublisher": {
|
|
59
|
+
"message": "DIRECT entry seller_type is not 'PUBLISHER'",
|
|
60
|
+
"description": "DIRECT relationship entries should have seller_type as 'PUBLISHER' or 'BOTH' in sellers.json",
|
|
61
|
+
"helpUrl": "/help/#direct-not-publisher"
|
|
62
|
+
},
|
|
63
|
+
"sellerIdNotUnique": {
|
|
64
|
+
"message": "Account ID '{{accountId}}' is duplicated",
|
|
65
|
+
"description": "The same account ID is used in multiple entries",
|
|
66
|
+
"helpUrl": "/help/#seller-id-not-unique"
|
|
67
|
+
},
|
|
68
|
+
"resellerNotIntermediary": {
|
|
69
|
+
"message": "RESELLER entry seller_type is not 'INTERMEDIARY'",
|
|
70
|
+
"description": "RESELLER relationship entries should have seller_type as 'INTERMEDIARY' or 'BOTH' in sellers.json",
|
|
71
|
+
"helpUrl": "/help/#reseller-not-intermediary"
|
|
72
|
+
},
|
|
73
|
+
"implimentedEntry": {
|
|
74
|
+
"message": "Duplicate entry",
|
|
75
|
+
"description": "Multiple ads.txt entries with the same content exist",
|
|
76
|
+
"helpUrl": "/help/#implimented-entry"
|
|
77
|
+
},
|
|
78
|
+
"noValidRecords": {
|
|
79
|
+
"message": "No valid records found",
|
|
80
|
+
"description": "The uploaded file or provided data does not contain any valid ads.txt records",
|
|
81
|
+
"helpUrl": "/help/#no-valid-records"
|
|
82
|
+
},
|
|
83
|
+
"parsingError": {
|
|
84
|
+
"message": "Parsing error: {{message}}",
|
|
85
|
+
"description": "An error occurred while parsing the file or data",
|
|
86
|
+
"helpUrl": "/help/#parsing-error"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"validation_errors": {
|
|
3
|
+
"missingFields": {
|
|
4
|
+
"message": "必須フィールドが不足しています",
|
|
5
|
+
"description": "ads.txtエントリには、ドメイン、アカウントID、関係性の3つの必須フィールドが必要です",
|
|
6
|
+
"helpUrl": "/help/#missing-fields"
|
|
7
|
+
},
|
|
8
|
+
"invalidFormat": {
|
|
9
|
+
"message": "無効なフォーマットです",
|
|
10
|
+
"description": "ads.txtエントリの形式が正しくありません。カンマで区切られた形式で入力してください",
|
|
11
|
+
"helpUrl": "/help/#invalid-format"
|
|
12
|
+
},
|
|
13
|
+
"invalidRelationship": {
|
|
14
|
+
"message": "無効な関係性です",
|
|
15
|
+
"description": "関係性は「DIRECT」または「RESELLER」である必要があります",
|
|
16
|
+
"helpUrl": "/help/#invalid-relationship"
|
|
17
|
+
},
|
|
18
|
+
"invalidDomain": {
|
|
19
|
+
"message": "無効なドメインです",
|
|
20
|
+
"description": "指定されたドメイン「{{domain}}」は有効なドメイン形式ではありません",
|
|
21
|
+
"helpUrl": "/help/#invalid-domain"
|
|
22
|
+
},
|
|
23
|
+
"emptyAccountId": {
|
|
24
|
+
"message": "アカウントIDが空です",
|
|
25
|
+
"description": "アカウントIDは必須フィールドです",
|
|
26
|
+
"helpUrl": "/help/#empty-account-id"
|
|
27
|
+
},
|
|
28
|
+
"emptyFile": {
|
|
29
|
+
"message": "ファイルが空です",
|
|
30
|
+
"description": "ads.txtファイルにコンテンツがありません",
|
|
31
|
+
"helpUrl": "/help/#empty-file"
|
|
32
|
+
},
|
|
33
|
+
"invalidCharacters": {
|
|
34
|
+
"message": "無効な文字が含まれています",
|
|
35
|
+
"description": "ads.txtファイルに印刷できない文字や制御文字が含まれています",
|
|
36
|
+
"helpUrl": "/help/#invalid-characters"
|
|
37
|
+
},
|
|
38
|
+
"noSellersJson": {
|
|
39
|
+
"message": "{{domain}}のsellers.jsonファイルが見つかりません",
|
|
40
|
+
"description": "指定された広告システムにsellers.jsonファイルが存在しません",
|
|
41
|
+
"helpUrl": "/help/#no-sellers-json"
|
|
42
|
+
},
|
|
43
|
+
"directAccountIdNotInSellersJson": {
|
|
44
|
+
"message": "DIRECTエントリのアカウントID「{{accountId}}」がsellers.jsonに見つかりません",
|
|
45
|
+
"description": "DIRECT関係のエントリは、対応するsellers.jsonファイルにアカウントIDが登録されている必要があります",
|
|
46
|
+
"helpUrl": "/help/#direct-account-id-not-in-sellers-json"
|
|
47
|
+
},
|
|
48
|
+
"resellerAccountIdNotInSellersJson": {
|
|
49
|
+
"message": "RESELLERエントリのアカウントID「{{accountId}}」がsellers.jsonに見つかりません",
|
|
50
|
+
"description": "RESELLER関係のエントリは、対応するsellers.jsonファイルにアカウントIDが登録されている必要があります",
|
|
51
|
+
"helpUrl": "/help/#reseller-account-id-not-in-sellers-json"
|
|
52
|
+
},
|
|
53
|
+
"domainMismatch": {
|
|
54
|
+
"message": "ドメインの不一致: {{sellerDomain}}",
|
|
55
|
+
"description": "sellers.jsonのドメインとads.txtのOWNERDOMAIN/MANAGERDOMAINが一致しません",
|
|
56
|
+
"helpUrl": "/help/#domain-mismatch"
|
|
57
|
+
},
|
|
58
|
+
"directNotPublisher": {
|
|
59
|
+
"message": "DIRECTエントリのseller_typeが「PUBLISHER」ではありません",
|
|
60
|
+
"description": "DIRECT関係のエントリは、sellers.jsonでseller_typeが「PUBLISHER」または「BOTH」である必要があります",
|
|
61
|
+
"helpUrl": "/help/#direct-not-publisher"
|
|
62
|
+
},
|
|
63
|
+
"sellerIdNotUnique": {
|
|
64
|
+
"message": "アカウントID「{{accountId}}」が重複しています",
|
|
65
|
+
"description": "同じアカウントIDが複数のエントリで使用されています",
|
|
66
|
+
"helpUrl": "/help/#seller-id-not-unique"
|
|
67
|
+
},
|
|
68
|
+
"resellerNotIntermediary": {
|
|
69
|
+
"message": "RESELLERエントリのseller_typeが「INTERMEDIARY」ではありません",
|
|
70
|
+
"description": "RESELLER関係のエントリは、sellers.jsonでseller_typeが「INTERMEDIARY」または「BOTH」である必要があります",
|
|
71
|
+
"helpUrl": "/help/#reseller-not-intermediary"
|
|
72
|
+
},
|
|
73
|
+
"implimentedEntry": {
|
|
74
|
+
"message": "重複したエントリです",
|
|
75
|
+
"description": "同じ内容のads.txtエントリが複数存在します",
|
|
76
|
+
"helpUrl": "/help/#implimented-entry"
|
|
77
|
+
},
|
|
78
|
+
"noValidRecords": {
|
|
79
|
+
"message": "有効なレコードがありません",
|
|
80
|
+
"description": "アップロードされたファイルまたは提供されたデータに有効なads.txtレコードが含まれていません",
|
|
81
|
+
"helpUrl": "/help/#no-valid-records"
|
|
82
|
+
},
|
|
83
|
+
"parsingError": {
|
|
84
|
+
"message": "解析エラー: {{message}}",
|
|
85
|
+
"description": "ファイルまたはデータの解析中にエラーが発生しました",
|
|
86
|
+
"helpUrl": "/help/#parsing-error"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message system for ads-txt-validator
|
|
3
|
+
* Provides internationalized messages and help links for validation results
|
|
4
|
+
*/
|
|
5
|
+
export interface ValidationMessage {
|
|
6
|
+
key: string;
|
|
7
|
+
severity: Severity;
|
|
8
|
+
message: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
helpUrl?: string;
|
|
11
|
+
placeholders: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface MessageData {
|
|
14
|
+
message: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
helpUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MessageProvider {
|
|
19
|
+
getMessage(key: string, locale?: string): MessageData | null;
|
|
20
|
+
formatMessage(key: string, placeholders: string[], locale?: string): ValidationMessage | null;
|
|
21
|
+
}
|
|
22
|
+
import { Severity } from './index';
|
|
23
|
+
declare const messages: {
|
|
24
|
+
readonly ja: {
|
|
25
|
+
validation_errors: {
|
|
26
|
+
missingFields: {
|
|
27
|
+
message: string;
|
|
28
|
+
description: string;
|
|
29
|
+
helpUrl: string;
|
|
30
|
+
};
|
|
31
|
+
invalidFormat: {
|
|
32
|
+
message: string;
|
|
33
|
+
description: string;
|
|
34
|
+
helpUrl: string;
|
|
35
|
+
};
|
|
36
|
+
invalidRelationship: {
|
|
37
|
+
message: string;
|
|
38
|
+
description: string;
|
|
39
|
+
helpUrl: string;
|
|
40
|
+
};
|
|
41
|
+
invalidDomain: {
|
|
42
|
+
message: string;
|
|
43
|
+
description: string;
|
|
44
|
+
helpUrl: string;
|
|
45
|
+
};
|
|
46
|
+
emptyAccountId: {
|
|
47
|
+
message: string;
|
|
48
|
+
description: string;
|
|
49
|
+
helpUrl: string;
|
|
50
|
+
};
|
|
51
|
+
emptyFile: {
|
|
52
|
+
message: string;
|
|
53
|
+
description: string;
|
|
54
|
+
helpUrl: string;
|
|
55
|
+
};
|
|
56
|
+
invalidCharacters: {
|
|
57
|
+
message: string;
|
|
58
|
+
description: string;
|
|
59
|
+
helpUrl: string;
|
|
60
|
+
};
|
|
61
|
+
noSellersJson: {
|
|
62
|
+
message: string;
|
|
63
|
+
description: string;
|
|
64
|
+
helpUrl: string;
|
|
65
|
+
};
|
|
66
|
+
directAccountIdNotInSellersJson: {
|
|
67
|
+
message: string;
|
|
68
|
+
description: string;
|
|
69
|
+
helpUrl: string;
|
|
70
|
+
};
|
|
71
|
+
resellerAccountIdNotInSellersJson: {
|
|
72
|
+
message: string;
|
|
73
|
+
description: string;
|
|
74
|
+
helpUrl: string;
|
|
75
|
+
};
|
|
76
|
+
domainMismatch: {
|
|
77
|
+
message: string;
|
|
78
|
+
description: string;
|
|
79
|
+
helpUrl: string;
|
|
80
|
+
};
|
|
81
|
+
directNotPublisher: {
|
|
82
|
+
message: string;
|
|
83
|
+
description: string;
|
|
84
|
+
helpUrl: string;
|
|
85
|
+
};
|
|
86
|
+
sellerIdNotUnique: {
|
|
87
|
+
message: string;
|
|
88
|
+
description: string;
|
|
89
|
+
helpUrl: string;
|
|
90
|
+
};
|
|
91
|
+
resellerNotIntermediary: {
|
|
92
|
+
message: string;
|
|
93
|
+
description: string;
|
|
94
|
+
helpUrl: string;
|
|
95
|
+
};
|
|
96
|
+
implimentedEntry: {
|
|
97
|
+
message: string;
|
|
98
|
+
description: string;
|
|
99
|
+
helpUrl: string;
|
|
100
|
+
};
|
|
101
|
+
noValidRecords: {
|
|
102
|
+
message: string;
|
|
103
|
+
description: string;
|
|
104
|
+
helpUrl: string;
|
|
105
|
+
};
|
|
106
|
+
parsingError: {
|
|
107
|
+
message: string;
|
|
108
|
+
description: string;
|
|
109
|
+
helpUrl: string;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
readonly en: {
|
|
114
|
+
validation_errors: {
|
|
115
|
+
missingFields: {
|
|
116
|
+
message: string;
|
|
117
|
+
description: string;
|
|
118
|
+
helpUrl: string;
|
|
119
|
+
};
|
|
120
|
+
invalidFormat: {
|
|
121
|
+
message: string;
|
|
122
|
+
description: string;
|
|
123
|
+
helpUrl: string;
|
|
124
|
+
};
|
|
125
|
+
invalidRelationship: {
|
|
126
|
+
message: string;
|
|
127
|
+
description: string;
|
|
128
|
+
helpUrl: string;
|
|
129
|
+
};
|
|
130
|
+
invalidDomain: {
|
|
131
|
+
message: string;
|
|
132
|
+
description: string;
|
|
133
|
+
helpUrl: string;
|
|
134
|
+
};
|
|
135
|
+
emptyAccountId: {
|
|
136
|
+
message: string;
|
|
137
|
+
description: string;
|
|
138
|
+
helpUrl: string;
|
|
139
|
+
};
|
|
140
|
+
emptyFile: {
|
|
141
|
+
message: string;
|
|
142
|
+
description: string;
|
|
143
|
+
helpUrl: string;
|
|
144
|
+
};
|
|
145
|
+
invalidCharacters: {
|
|
146
|
+
message: string;
|
|
147
|
+
description: string;
|
|
148
|
+
helpUrl: string;
|
|
149
|
+
};
|
|
150
|
+
noSellersJson: {
|
|
151
|
+
message: string;
|
|
152
|
+
description: string;
|
|
153
|
+
helpUrl: string;
|
|
154
|
+
};
|
|
155
|
+
directAccountIdNotInSellersJson: {
|
|
156
|
+
message: string;
|
|
157
|
+
description: string;
|
|
158
|
+
helpUrl: string;
|
|
159
|
+
};
|
|
160
|
+
resellerAccountIdNotInSellersJson: {
|
|
161
|
+
message: string;
|
|
162
|
+
description: string;
|
|
163
|
+
helpUrl: string;
|
|
164
|
+
};
|
|
165
|
+
domainMismatch: {
|
|
166
|
+
message: string;
|
|
167
|
+
description: string;
|
|
168
|
+
helpUrl: string;
|
|
169
|
+
};
|
|
170
|
+
directNotPublisher: {
|
|
171
|
+
message: string;
|
|
172
|
+
description: string;
|
|
173
|
+
helpUrl: string;
|
|
174
|
+
};
|
|
175
|
+
sellerIdNotUnique: {
|
|
176
|
+
message: string;
|
|
177
|
+
description: string;
|
|
178
|
+
helpUrl: string;
|
|
179
|
+
};
|
|
180
|
+
resellerNotIntermediary: {
|
|
181
|
+
message: string;
|
|
182
|
+
description: string;
|
|
183
|
+
helpUrl: string;
|
|
184
|
+
};
|
|
185
|
+
implimentedEntry: {
|
|
186
|
+
message: string;
|
|
187
|
+
description: string;
|
|
188
|
+
helpUrl: string;
|
|
189
|
+
};
|
|
190
|
+
noValidRecords: {
|
|
191
|
+
message: string;
|
|
192
|
+
description: string;
|
|
193
|
+
helpUrl: string;
|
|
194
|
+
};
|
|
195
|
+
parsingError: {
|
|
196
|
+
message: string;
|
|
197
|
+
description: string;
|
|
198
|
+
helpUrl: string;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
export type SupportedLocale = keyof typeof messages;
|
|
204
|
+
/**
|
|
205
|
+
* Configuration for message provider
|
|
206
|
+
*/
|
|
207
|
+
export interface MessageConfig {
|
|
208
|
+
defaultLocale?: SupportedLocale;
|
|
209
|
+
baseUrl?: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Default message provider implementation
|
|
213
|
+
*/
|
|
214
|
+
export declare class DefaultMessageProvider implements MessageProvider {
|
|
215
|
+
private defaultLocale;
|
|
216
|
+
private baseUrl?;
|
|
217
|
+
constructor(defaultLocale?: SupportedLocale, config?: MessageConfig);
|
|
218
|
+
/**
|
|
219
|
+
* Get raw message data for a validation key
|
|
220
|
+
*/
|
|
221
|
+
getMessage(key: string, locale?: string): MessageData | null;
|
|
222
|
+
/**
|
|
223
|
+
* Format help URL with base URL if configured
|
|
224
|
+
*/
|
|
225
|
+
private formatHelpUrl;
|
|
226
|
+
/**
|
|
227
|
+
* Format a message with placeholders and create a ValidationMessage
|
|
228
|
+
*/
|
|
229
|
+
formatMessage(key: string, placeholders?: string[], locale?: string): ValidationMessage | null;
|
|
230
|
+
/**
|
|
231
|
+
* Replace {{placeholder}} and {{0}}, {{1}} style placeholders
|
|
232
|
+
*/
|
|
233
|
+
private replacePlaceholders;
|
|
234
|
+
/**
|
|
235
|
+
* Determine severity from validation key
|
|
236
|
+
*/
|
|
237
|
+
private getSeverityFromKey;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Set the global message provider
|
|
241
|
+
*/
|
|
242
|
+
export declare function setMessageProvider(provider: MessageProvider): void;
|
|
243
|
+
/**
|
|
244
|
+
* Configure the global message provider with baseUrl
|
|
245
|
+
*/
|
|
246
|
+
export declare function configureMessages(config: MessageConfig): void;
|
|
247
|
+
/**
|
|
248
|
+
* Get the current message provider
|
|
249
|
+
*/
|
|
250
|
+
export declare function getMessageProvider(): MessageProvider;
|
|
251
|
+
/**
|
|
252
|
+
* Convenience function to create a validation message
|
|
253
|
+
*/
|
|
254
|
+
export declare function createValidationMessage(key: string, placeholders?: string[], locale?: string): ValidationMessage | null;
|
|
255
|
+
/**
|
|
256
|
+
* Check if a locale is supported
|
|
257
|
+
*/
|
|
258
|
+
export declare function isSupportedLocale(locale: string): locale is SupportedLocale;
|
|
259
|
+
/**
|
|
260
|
+
* Get list of supported locales
|
|
261
|
+
*/
|
|
262
|
+
export declare function getSupportedLocales(): SupportedLocale[];
|
|
263
|
+
export {};
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Message system for ads-txt-validator
|
|
4
|
+
* Provides internationalized messages and help links for validation results
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DefaultMessageProvider = void 0;
|
|
11
|
+
exports.setMessageProvider = setMessageProvider;
|
|
12
|
+
exports.configureMessages = configureMessages;
|
|
13
|
+
exports.getMessageProvider = getMessageProvider;
|
|
14
|
+
exports.createValidationMessage = createValidationMessage;
|
|
15
|
+
exports.isSupportedLocale = isSupportedLocale;
|
|
16
|
+
exports.getSupportedLocales = getSupportedLocales;
|
|
17
|
+
const validation_json_1 = __importDefault(require("./locales/ja/validation.json"));
|
|
18
|
+
const validation_json_2 = __importDefault(require("./locales/en/validation.json"));
|
|
19
|
+
// Import severity from main index
|
|
20
|
+
const index_1 = require("./index");
|
|
21
|
+
// Message resources
|
|
22
|
+
const messages = {
|
|
23
|
+
ja: validation_json_1.default,
|
|
24
|
+
en: validation_json_2.default,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Default message provider implementation
|
|
28
|
+
*/
|
|
29
|
+
class DefaultMessageProvider {
|
|
30
|
+
constructor(defaultLocale = 'ja', config) {
|
|
31
|
+
this.defaultLocale = 'ja';
|
|
32
|
+
this.defaultLocale = config?.defaultLocale || defaultLocale;
|
|
33
|
+
this.baseUrl = config?.baseUrl;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get raw message data for a validation key
|
|
37
|
+
*/
|
|
38
|
+
getMessage(key, locale) {
|
|
39
|
+
const targetLocale = locale || this.defaultLocale;
|
|
40
|
+
const messageBundle = messages[targetLocale] || messages[this.defaultLocale];
|
|
41
|
+
const messageData = messageBundle.validation_errors[key];
|
|
42
|
+
if (!messageData) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
message: messageData.message,
|
|
47
|
+
description: messageData.description,
|
|
48
|
+
helpUrl: this.formatHelpUrl(messageData.helpUrl),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Format help URL with base URL if configured
|
|
53
|
+
*/
|
|
54
|
+
formatHelpUrl(helpUrl) {
|
|
55
|
+
if (!helpUrl) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
// If helpUrl is already a full URL (starts with http/https), return as-is
|
|
59
|
+
if (helpUrl.startsWith('http://') || helpUrl.startsWith('https://')) {
|
|
60
|
+
return helpUrl;
|
|
61
|
+
}
|
|
62
|
+
// If baseUrl is configured and helpUrl is relative, combine them
|
|
63
|
+
if (this.baseUrl && helpUrl.startsWith('/')) {
|
|
64
|
+
return `${this.baseUrl.replace(/\/$/, '')}${helpUrl}`;
|
|
65
|
+
}
|
|
66
|
+
// Return helpUrl as-is for other cases
|
|
67
|
+
return helpUrl;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Format a message with placeholders and create a ValidationMessage
|
|
71
|
+
*/
|
|
72
|
+
formatMessage(key, placeholders = [], locale) {
|
|
73
|
+
const messageData = this.getMessage(key, locale);
|
|
74
|
+
if (!messageData) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
// Replace placeholders in the message
|
|
78
|
+
const formattedMessage = this.replacePlaceholders(messageData.message, placeholders);
|
|
79
|
+
const formattedDescription = messageData.description
|
|
80
|
+
? this.replacePlaceholders(messageData.description, placeholders)
|
|
81
|
+
: undefined;
|
|
82
|
+
// Determine severity based on key
|
|
83
|
+
const severity = this.getSeverityFromKey(key);
|
|
84
|
+
return {
|
|
85
|
+
key,
|
|
86
|
+
severity,
|
|
87
|
+
message: formattedMessage,
|
|
88
|
+
description: formattedDescription,
|
|
89
|
+
helpUrl: messageData.helpUrl,
|
|
90
|
+
placeholders,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Replace {{placeholder}} and {{0}}, {{1}} style placeholders
|
|
95
|
+
*/
|
|
96
|
+
replacePlaceholders(template, placeholders) {
|
|
97
|
+
let result = template;
|
|
98
|
+
// Replace numbered placeholders like {{0}}, {{1}}
|
|
99
|
+
result = result.replace(/\{\{(\d+)\}\}/g, (match, index) => {
|
|
100
|
+
const placeholderIndex = parseInt(index, 10);
|
|
101
|
+
return placeholders[placeholderIndex] || match;
|
|
102
|
+
});
|
|
103
|
+
// Replace named placeholders
|
|
104
|
+
if (placeholders.length > 0) {
|
|
105
|
+
// Common placeholder names
|
|
106
|
+
const placeholderNames = ['domain', 'accountId', 'sellerDomain', 'accountType'];
|
|
107
|
+
placeholderNames.forEach((name, index) => {
|
|
108
|
+
if (index < placeholders.length) {
|
|
109
|
+
result = result.replace(new RegExp(`\\{\\{${name}\\}\\}`, 'g'), placeholders[index]);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Determine severity from validation key
|
|
117
|
+
*/
|
|
118
|
+
getSeverityFromKey(key) {
|
|
119
|
+
// Keys that should be errors
|
|
120
|
+
const errorKeys = [
|
|
121
|
+
'missingFields',
|
|
122
|
+
'invalidFormat',
|
|
123
|
+
'invalidRelationship',
|
|
124
|
+
'invalidDomain',
|
|
125
|
+
'emptyAccountId',
|
|
126
|
+
'emptyFile',
|
|
127
|
+
'invalidCharacters',
|
|
128
|
+
'directAccountIdNotInSellersJson',
|
|
129
|
+
'resellerAccountIdNotInSellersJson',
|
|
130
|
+
];
|
|
131
|
+
if (errorKeys.includes(key)) {
|
|
132
|
+
return index_1.Severity.ERROR;
|
|
133
|
+
}
|
|
134
|
+
// Keys that should be warnings
|
|
135
|
+
const warningKeys = [
|
|
136
|
+
'noSellersJson',
|
|
137
|
+
'domainMismatch',
|
|
138
|
+
'directNotPublisher',
|
|
139
|
+
'resellerNotIntermediary',
|
|
140
|
+
'sellerIdNotUnique',
|
|
141
|
+
];
|
|
142
|
+
if (warningKeys.includes(key)) {
|
|
143
|
+
return index_1.Severity.WARNING;
|
|
144
|
+
}
|
|
145
|
+
// Default to info
|
|
146
|
+
return index_1.Severity.INFO;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
exports.DefaultMessageProvider = DefaultMessageProvider;
|
|
150
|
+
/**
|
|
151
|
+
* Global message provider instance
|
|
152
|
+
*/
|
|
153
|
+
let globalMessageProvider = new DefaultMessageProvider();
|
|
154
|
+
/**
|
|
155
|
+
* Set the global message provider
|
|
156
|
+
*/
|
|
157
|
+
function setMessageProvider(provider) {
|
|
158
|
+
globalMessageProvider = provider;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Configure the global message provider with baseUrl
|
|
162
|
+
*/
|
|
163
|
+
function configureMessages(config) {
|
|
164
|
+
globalMessageProvider = new DefaultMessageProvider(config.defaultLocale, config);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the current message provider
|
|
168
|
+
*/
|
|
169
|
+
function getMessageProvider() {
|
|
170
|
+
return globalMessageProvider;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Convenience function to create a validation message
|
|
174
|
+
*/
|
|
175
|
+
function createValidationMessage(key, placeholders = [], locale) {
|
|
176
|
+
return globalMessageProvider.formatMessage(key, placeholders, locale);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check if a locale is supported
|
|
180
|
+
*/
|
|
181
|
+
function isSupportedLocale(locale) {
|
|
182
|
+
return locale in messages;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get list of supported locales
|
|
186
|
+
*/
|
|
187
|
+
function getSupportedLocales() {
|
|
188
|
+
return Object.keys(messages);
|
|
189
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adstxt-validator",
|
|
3
|
+
"version": "1.2.3",
|
|
4
|
+
"description": "A TypeScript library for validating ads.txt files and sellers.json files",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/**/*",
|
|
10
|
+
"src/locales/**/*.json",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"lint": "eslint src --ext .ts",
|
|
17
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
18
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
19
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"test": "echo \"Tests will be implemented in future versions\" && exit 0"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"ads.txt",
|
|
25
|
+
"sellers.json",
|
|
26
|
+
"advertising",
|
|
27
|
+
"validation",
|
|
28
|
+
"typescript"
|
|
29
|
+
],
|
|
30
|
+
"author": "Yoshihiko Miyaichi",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/miyaichi/adstxt-validator.git"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"psl": "^1.9.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@eslint/js": "^9.39.2",
|
|
44
|
+
"@types/node": "^20.0.0",
|
|
45
|
+
"@types/psl": "^1.1.3",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
|
47
|
+
"@typescript-eslint/parser": "^8.49.0",
|
|
48
|
+
"eslint": "^9.39.2",
|
|
49
|
+
"eslint-config-prettier": "^10.1.8",
|
|
50
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
51
|
+
"prettier": "^3.7.4",
|
|
52
|
+
"typescript": "^5.0.4",
|
|
53
|
+
"typescript-eslint": "^8.49.0"
|
|
54
|
+
}
|
|
55
|
+
}
|