@fgv/ts-bcp47 5.1.0-2 → 5.1.0-4
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/dist/data/bcp/overrides.json +21 -0
- package/dist/data/unsd/m49.json +3723 -0
- package/dist/index.browser.js +30 -0
- package/dist/index.js +28 -0
- package/dist/packlets/bcp47/bcp47Subtags/converters.js +32 -0
- package/dist/packlets/bcp47/bcp47Subtags/index.js +26 -0
- package/dist/packlets/bcp47/bcp47Subtags/model.js +23 -0
- package/dist/packlets/bcp47/bcp47Subtags/validate.js +48 -0
- package/dist/packlets/bcp47/common.js +53 -0
- package/dist/packlets/bcp47/helpers.js +96 -0
- package/dist/packlets/bcp47/index.js +32 -0
- package/dist/packlets/bcp47/languageRegistryData.js +202 -0
- package/dist/packlets/bcp47/languageTag.js +363 -0
- package/dist/packlets/bcp47/languageTagParser.js +275 -0
- package/dist/packlets/bcp47/match/chooser.js +88 -0
- package/dist/packlets/bcp47/match/common.js +49 -0
- package/dist/packlets/bcp47/match/index.js +26 -0
- package/dist/packlets/bcp47/match/similarity.js +205 -0
- package/dist/packlets/bcp47/normalization/baseNormalizer.js +89 -0
- package/dist/packlets/bcp47/normalization/canonicalNormalizer.js +86 -0
- package/dist/packlets/bcp47/normalization/common.js +77 -0
- package/dist/packlets/bcp47/normalization/index.js +27 -0
- package/dist/packlets/bcp47/normalization/normalizeTag.js +101 -0
- package/dist/packlets/bcp47/normalization/preferredTagNormalizer.js +177 -0
- package/dist/packlets/bcp47/overrides/converters.js +49 -0
- package/dist/packlets/bcp47/overrides/defaultRegistries.js +38 -0
- package/dist/packlets/bcp47/overrides/index.js +25 -0
- package/dist/packlets/bcp47/overrides/model.js +23 -0
- package/dist/packlets/bcp47/overrides/overridesRegistry.js +83 -0
- package/dist/packlets/bcp47/validation/baseValidator.js +86 -0
- package/dist/packlets/bcp47/validation/common.js +77 -0
- package/dist/packlets/bcp47/validation/index.js +29 -0
- package/dist/packlets/bcp47/validation/isCanonical.js +79 -0
- package/dist/packlets/bcp47/validation/isInPreferredForm.js +46 -0
- package/dist/packlets/bcp47/validation/isStrictlyValid.js +94 -0
- package/dist/packlets/bcp47/validation/isValid.js +92 -0
- package/dist/packlets/bcp47/validation/isWellFormed.js +75 -0
- package/dist/packlets/bcp47/validation/validateTag.js +153 -0
- package/dist/packlets/iana/common/converters.js +58 -0
- package/dist/packlets/iana/common/model.js +23 -0
- package/dist/packlets/iana/common/registeredItems.js +120 -0
- package/dist/packlets/iana/common/utils.js +30 -0
- package/dist/packlets/iana/common/validate.js +59 -0
- package/dist/packlets/iana/converters.js +25 -0
- package/dist/packlets/iana/defaultRegistries.js +38 -0
- package/dist/packlets/iana/iana-data-embedded.js +60 -0
- package/dist/packlets/iana/index.browser.js +34 -0
- package/dist/packlets/iana/index.js +34 -0
- package/dist/packlets/iana/jar/converters.js +25 -0
- package/dist/packlets/iana/jar/index.js +26 -0
- package/dist/packlets/iana/jar/jarConverters.js +60 -0
- package/dist/packlets/iana/jar/jarModel.js +23 -0
- package/dist/packlets/iana/jar/language-subtags/converters.js +25 -0
- package/dist/packlets/iana/jar/language-subtags/index.js +26 -0
- package/dist/packlets/iana/jar/language-subtags/model.js +25 -0
- package/dist/packlets/iana/jar/language-subtags/registry/converters.js +180 -0
- package/dist/packlets/iana/jar/language-subtags/registry/index.js +26 -0
- package/dist/packlets/iana/jar/language-subtags/registry/model.js +43 -0
- package/dist/packlets/iana/jar/language-subtags/tags/converters.js +101 -0
- package/dist/packlets/iana/jar/language-subtags/tags/index.js +27 -0
- package/dist/packlets/iana/jar/language-subtags/tags/model.js +23 -0
- package/dist/packlets/iana/jar/language-subtags/tags/tagValidation.js +66 -0
- package/dist/packlets/iana/jar/language-subtags/tags/validate.js +85 -0
- package/dist/packlets/iana/jar/model.js +25 -0
- package/dist/packlets/iana/language-subtags/common.js +23 -0
- package/dist/packlets/iana/language-subtags/converters.js +182 -0
- package/dist/packlets/iana/language-subtags/index.browser.js +30 -0
- package/dist/packlets/iana/language-subtags/index.js +29 -0
- package/dist/packlets/iana/language-subtags/jarConverters.js +288 -0
- package/dist/packlets/iana/language-subtags/model.js +23 -0
- package/dist/packlets/iana/language-subtags/scope.js +169 -0
- package/dist/packlets/iana/language-subtags/subtagRegistry.js +108 -0
- package/dist/packlets/iana/language-subtags/validate.js +23 -0
- package/dist/packlets/iana/language-tag-extensions/converters.js +59 -0
- package/dist/packlets/iana/language-tag-extensions/extensionsRegistry.js +64 -0
- package/dist/packlets/iana/language-tag-extensions/extensionsScope.js +50 -0
- package/dist/packlets/iana/language-tag-extensions/index.js +28 -0
- package/dist/packlets/iana/language-tag-extensions/jarConverters.js +143 -0
- package/dist/packlets/iana/language-tag-extensions/model.js +24 -0
- package/dist/packlets/iana/language-tag-extensions/validate.js +33 -0
- package/dist/packlets/iana/languageRegistries.js +80 -0
- package/dist/packlets/iana/languageRegistriesFileLoader.js +73 -0
- package/dist/packlets/iana/languageRegistriesLoader.js +113 -0
- package/dist/packlets/iana/model.js +25 -0
- package/dist/packlets/iana/validate.js +23 -0
- package/dist/packlets/unsd/areas.js +92 -0
- package/dist/packlets/unsd/common.js +23 -0
- package/dist/packlets/unsd/csv/converters.js +75 -0
- package/dist/packlets/unsd/csv/index.js +25 -0
- package/dist/packlets/unsd/csv/model.js +23 -0
- package/dist/packlets/unsd/defaultRegistries.js +38 -0
- package/dist/packlets/unsd/index.js +27 -0
- package/dist/packlets/unsd/regionCodes.js +115 -0
- package/dist/packlets/unsd/regions.js +71 -0
- package/dist/packlets/utils/index.js +24 -0
- package/dist/packlets/utils/jsonHelpers.js +25 -0
- package/dist/packlets/utils/public.js +24 -0
- package/dist/packlets/utils/validationHelpers.js +116 -0
- package/dist/test/unit/bcp47/commonTestCases.js +475 -0
- package/dist/test/unit/bcp47/languageTagHelpers.js +178 -0
- package/dist/test/unit/iana/testConstants.js +68 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +36 -31
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { LanguageTag } from '../languageTag';
|
|
23
|
+
import { LanguageSimilarityMatcher } from './similarity';
|
|
24
|
+
/**
|
|
25
|
+
* Default values for a{@link Bcp47.LanguageFilterOptions}.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export const defaultLanguageChooserOptions = Object.freeze({
|
|
29
|
+
use: 'availableLanguage',
|
|
30
|
+
filter: 'primaryLanguage'
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Helper to compare a list of 'desired' languages to a list of 'available' language
|
|
34
|
+
* and return the intersection in order of preference, taking tag semantics into account.
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export class LanguageChooser {
|
|
38
|
+
constructor(iana) {
|
|
39
|
+
this._matcher = new LanguageSimilarityMatcher(iana);
|
|
40
|
+
}
|
|
41
|
+
chooseLanguageTagsWithDetails(desiredLanguages, availableLanguages, options) {
|
|
42
|
+
var _a;
|
|
43
|
+
const matched = new Map();
|
|
44
|
+
const decrement = desiredLanguages.length < 10 ? 0.1 : 1.0 / desiredLanguages.length;
|
|
45
|
+
let base = 1.0;
|
|
46
|
+
// fill any missing fields from the default
|
|
47
|
+
options = Object.assign(Object.assign({}, defaultLanguageChooserOptions), options);
|
|
48
|
+
for (const want of desiredLanguages) {
|
|
49
|
+
base -= decrement;
|
|
50
|
+
for (const have of availableLanguages) {
|
|
51
|
+
const similarity = this._matcher.matchLanguageTags(want, have);
|
|
52
|
+
if (similarity > 0.0) {
|
|
53
|
+
const quality = base + similarity * decrement;
|
|
54
|
+
const languageTag = options.use === 'availableLanguage' ? have : want;
|
|
55
|
+
const tag = languageTag.tag;
|
|
56
|
+
const key = options.filter === 'primaryLanguage' ? (_a = languageTag.subtags.primaryLanguage) !== null && _a !== void 0 ? _a : tag : tag;
|
|
57
|
+
const match = {
|
|
58
|
+
quality,
|
|
59
|
+
tag,
|
|
60
|
+
languageTag
|
|
61
|
+
};
|
|
62
|
+
const existing = matched.get(key);
|
|
63
|
+
if (!existing || existing.quality < quality) {
|
|
64
|
+
matched.set(key, match);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const values = Array.from(matched.values());
|
|
70
|
+
if (values.length > 1) {
|
|
71
|
+
// want descending order
|
|
72
|
+
values.sort((m1, m2) => m2.quality - m1.quality);
|
|
73
|
+
}
|
|
74
|
+
else if (values.length === 0 && options.ultimateFallback) {
|
|
75
|
+
const languageTag = options.ultimateFallback instanceof LanguageTag
|
|
76
|
+
? options.ultimateFallback
|
|
77
|
+
: LanguageTag.create(options.ultimateFallback).orDefault();
|
|
78
|
+
if (languageTag) {
|
|
79
|
+
return [{ languageTag, tag: languageTag.tag, quality: 0 }];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return values;
|
|
83
|
+
}
|
|
84
|
+
filterLanguageTags(desiredLanguages, availableLanguages, options) {
|
|
85
|
+
return this.chooseLanguageTagsWithDetails(desiredLanguages, availableLanguages, options).map((t) => t.languageTag);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=chooser.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
/* eslint-disable @rushstack/typedef-var */
|
|
23
|
+
/**
|
|
24
|
+
* Penalty for a mismatched value for some subtags.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export const subtagMismatchPenalty = {
|
|
28
|
+
private: 0.05,
|
|
29
|
+
extension: 0.04,
|
|
30
|
+
variant: 0.1
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Common levels of match quality for a single language match.
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export const tagSimilarity = {
|
|
37
|
+
exact: 1.0,
|
|
38
|
+
variant: 0.9,
|
|
39
|
+
region: 0.8,
|
|
40
|
+
macroRegion: 0.65,
|
|
41
|
+
neutralRegion: 0.5,
|
|
42
|
+
preferredAffinity: 0.45,
|
|
43
|
+
affinity: 0.4,
|
|
44
|
+
preferredRegion: 0.35,
|
|
45
|
+
sibling: 0.3,
|
|
46
|
+
undetermined: 0.1,
|
|
47
|
+
none: 0
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
// istanbul ignore file
|
|
23
|
+
export { LanguageChooser } from './chooser';
|
|
24
|
+
export * from './common';
|
|
25
|
+
export { LanguageSimilarityMatcher } from './similarity';
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import * as Iana from '../../iana';
|
|
23
|
+
import * as Unsd from '../../unsd';
|
|
24
|
+
import { DefaultRegistries } from '../overrides';
|
|
25
|
+
import { GlobalRegion } from '../common';
|
|
26
|
+
import { tagSimilarity } from './common';
|
|
27
|
+
/**
|
|
28
|
+
* Helper to compare two language tags to determine how closely related they are,
|
|
29
|
+
* applying normalization and language semantics as appropriate.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export class LanguageSimilarityMatcher {
|
|
33
|
+
constructor(iana) {
|
|
34
|
+
/* c8 ignore next */
|
|
35
|
+
this.iana = iana !== null && iana !== void 0 ? iana : Iana.DefaultRegistries.languageRegistries;
|
|
36
|
+
this.unsd = Unsd.DefaultRegistries.regionCodes;
|
|
37
|
+
this.overrides = DefaultRegistries.overridesRegistry;
|
|
38
|
+
}
|
|
39
|
+
matchLanguageTags(t1, t2) {
|
|
40
|
+
// no primary tag is either all private or grandfathered, which must match
|
|
41
|
+
// exactly.
|
|
42
|
+
if (!t1.subtags.primaryLanguage || !t2.subtags.primaryLanguage) {
|
|
43
|
+
return t1.toString().toLowerCase() === t2.toString().toLowerCase()
|
|
44
|
+
? tagSimilarity.exact
|
|
45
|
+
: tagSimilarity.none;
|
|
46
|
+
}
|
|
47
|
+
let quality = this.matchPrimaryLanguage(t1, t2);
|
|
48
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchExtlang(t1, t2), quality) : quality;
|
|
49
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchScript(t1, t2), quality) : quality;
|
|
50
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchRegion(t1, t2), quality) : quality;
|
|
51
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchVariants(t1, t2), quality) : quality;
|
|
52
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchExtensions(t1, t2), quality) : quality;
|
|
53
|
+
quality = quality > tagSimilarity.none ? Math.min(this.matchPrivateUseTags(t1, t2), quality) : quality;
|
|
54
|
+
return quality;
|
|
55
|
+
}
|
|
56
|
+
matchPrimaryLanguage(lt1, lt2) {
|
|
57
|
+
var _a, _b;
|
|
58
|
+
/* c8 ignore next 2 */
|
|
59
|
+
const l1 = (_a = lt1.subtags.primaryLanguage) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
60
|
+
const l2 = (_b = lt2.subtags.primaryLanguage) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
61
|
+
if (l1 === l2) {
|
|
62
|
+
return tagSimilarity.exact;
|
|
63
|
+
}
|
|
64
|
+
if (lt1.isUndetermined || lt2.isUndetermined) {
|
|
65
|
+
return tagSimilarity.undetermined;
|
|
66
|
+
}
|
|
67
|
+
return tagSimilarity.none;
|
|
68
|
+
}
|
|
69
|
+
matchExtlang(lt1, lt2) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
if (((_a = lt1.subtags.extlangs) === null || _a === void 0 ? void 0 : _a.length) !== ((_b = lt2.subtags.extlangs) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
72
|
+
return tagSimilarity.none;
|
|
73
|
+
}
|
|
74
|
+
if (lt1.subtags.extlangs) {
|
|
75
|
+
for (let i = 0; i < lt1.subtags.extlangs.length; i++) {
|
|
76
|
+
if (lt1.subtags.extlangs[i].toLowerCase() !== lt2.subtags.extlangs[i].toLowerCase()) {
|
|
77
|
+
return tagSimilarity.none;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return tagSimilarity.exact;
|
|
82
|
+
}
|
|
83
|
+
matchScript(lt1, lt2) {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
const s1 = (_a = lt1.effectiveScript) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
86
|
+
const s2 = (_b = lt2.effectiveScript) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
87
|
+
if (s1 === s2) {
|
|
88
|
+
return tagSimilarity.exact;
|
|
89
|
+
}
|
|
90
|
+
if (lt1.isUndetermined || lt2.isUndetermined) {
|
|
91
|
+
return tagSimilarity.undetermined;
|
|
92
|
+
}
|
|
93
|
+
return tagSimilarity.none;
|
|
94
|
+
}
|
|
95
|
+
matchRegion(lt1, lt2) {
|
|
96
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
97
|
+
const r1 = (_a = lt1.subtags.region) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
98
|
+
const r2 = (_b = lt2.subtags.region) === null || _b === void 0 ? void 0 : _b.toUpperCase();
|
|
99
|
+
if (r1 === r2) {
|
|
100
|
+
return tagSimilarity.exact;
|
|
101
|
+
}
|
|
102
|
+
// region 001 is equivalent to neutral (no region)
|
|
103
|
+
if (r1 === GlobalRegion || r2 === GlobalRegion) {
|
|
104
|
+
// if one tag is 001 and the other in neutral, exact match
|
|
105
|
+
// otherwise, one tag is 001 so neutral region match
|
|
106
|
+
return !r1 || !r2 ? tagSimilarity.exact : tagSimilarity.neutralRegion;
|
|
107
|
+
}
|
|
108
|
+
if (!r1 || !r2) {
|
|
109
|
+
return tagSimilarity.neutralRegion;
|
|
110
|
+
}
|
|
111
|
+
// macro-region match
|
|
112
|
+
const r1IsMacroRegion = Iana.Validate.unM49RegionCode.isWellFormed(r1);
|
|
113
|
+
const r2IsMacroRegion = Iana.Validate.unM49RegionCode.isWellFormed(r2);
|
|
114
|
+
if (r1IsMacroRegion || r2IsMacroRegion) {
|
|
115
|
+
let contained;
|
|
116
|
+
let container;
|
|
117
|
+
if (r1IsMacroRegion) {
|
|
118
|
+
container = this.unsd.regions.tryGetRegion(r1);
|
|
119
|
+
contained =
|
|
120
|
+
(_c = this.unsd.areas.tryGetAlpha2Area(r2)) !== null && _c !== void 0 ? _c : this.unsd.tryGetRegionOrArea(r2);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
container = this.unsd.regions.tryGetRegion(r2);
|
|
124
|
+
contained = this.unsd.areas.tryGetAlpha2Area(r1);
|
|
125
|
+
}
|
|
126
|
+
if (container && contained) {
|
|
127
|
+
if (this.unsd.getIsContained(container, contained)) {
|
|
128
|
+
return tagSimilarity.macroRegion;
|
|
129
|
+
}
|
|
130
|
+
// if they're both regions, also check to see if the second region contains the
|
|
131
|
+
// first
|
|
132
|
+
if (contained.tier !== 'area' && this.unsd.getIsContained(contained, container)) {
|
|
133
|
+
return tagSimilarity.macroRegion;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/* c8 ignore next 6 */
|
|
138
|
+
const o1 = this.overrides.overrides.get((_d = lt1.subtags.primaryLanguage) === null || _d === void 0 ? void 0 : _d.toLowerCase());
|
|
139
|
+
const o2 = this.overrides.overrides.get((_e = lt2.subtags.primaryLanguage) === null || _e === void 0 ? void 0 : _e.toLowerCase());
|
|
140
|
+
// orthographic affinity
|
|
141
|
+
if (o1 && o2) {
|
|
142
|
+
/* c8 ignore next 2 */
|
|
143
|
+
const a1 = (_g = (_f = o1.affinity) === null || _f === void 0 ? void 0 : _f.get(r1)) !== null && _g !== void 0 ? _g : o1.defaultAffinity;
|
|
144
|
+
const a2 = (_j = (_h = o2.affinity) === null || _h === void 0 ? void 0 : _h.get(r2)) !== null && _j !== void 0 ? _j : o2.defaultAffinity;
|
|
145
|
+
if (a1 && a2) {
|
|
146
|
+
if (r1 === a2.toUpperCase() || r2 === a1.toUpperCase()) {
|
|
147
|
+
return tagSimilarity.preferredAffinity;
|
|
148
|
+
}
|
|
149
|
+
if (a1 === a2) {
|
|
150
|
+
return tagSimilarity.affinity;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// preferred region
|
|
155
|
+
if ((o1 === null || o1 === void 0 ? void 0 : o1.preferredRegion) === r1 || (o2 === null || o2 === void 0 ? void 0 : o2.preferredRegion) === r2) {
|
|
156
|
+
return tagSimilarity.preferredRegion;
|
|
157
|
+
}
|
|
158
|
+
return tagSimilarity.sibling;
|
|
159
|
+
}
|
|
160
|
+
matchVariants(lt1, lt2) {
|
|
161
|
+
var _a, _b;
|
|
162
|
+
if (((_a = lt1.subtags.variants) === null || _a === void 0 ? void 0 : _a.length) !== ((_b = lt2.subtags.variants) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
163
|
+
return tagSimilarity.region;
|
|
164
|
+
}
|
|
165
|
+
if (lt1.subtags.variants) {
|
|
166
|
+
for (let i = 0; i < lt1.subtags.variants.length; i++) {
|
|
167
|
+
if (lt1.subtags.variants[i].toLowerCase() !== lt2.subtags.variants[i].toLowerCase()) {
|
|
168
|
+
return tagSimilarity.region;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return tagSimilarity.exact;
|
|
173
|
+
}
|
|
174
|
+
matchExtensions(lt1, lt2) {
|
|
175
|
+
var _a, _b;
|
|
176
|
+
if (((_a = lt1.subtags.extensions) === null || _a === void 0 ? void 0 : _a.length) !== ((_b = lt2.subtags.extensions) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
177
|
+
return tagSimilarity.variant;
|
|
178
|
+
}
|
|
179
|
+
if (lt1.subtags.extensions) {
|
|
180
|
+
for (let i = 0; i < lt1.subtags.extensions.length; i++) {
|
|
181
|
+
if (lt1.subtags.extensions[i].singleton.toLowerCase() !==
|
|
182
|
+
lt2.subtags.extensions[i].singleton.toLowerCase() ||
|
|
183
|
+
lt1.subtags.extensions[i].value.toLowerCase() !== lt2.subtags.extensions[i].value.toLowerCase()) {
|
|
184
|
+
return tagSimilarity.variant;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return tagSimilarity.exact;
|
|
189
|
+
}
|
|
190
|
+
matchPrivateUseTags(lt1, lt2) {
|
|
191
|
+
var _a, _b;
|
|
192
|
+
if (((_a = lt1.subtags.privateUse) === null || _a === void 0 ? void 0 : _a.length) !== ((_b = lt2.subtags.privateUse) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
193
|
+
return tagSimilarity.variant;
|
|
194
|
+
}
|
|
195
|
+
if (lt1.subtags.privateUse) {
|
|
196
|
+
for (let i = 0; i < lt1.subtags.privateUse.length; i++) {
|
|
197
|
+
if (lt1.subtags.privateUse[i].toLowerCase() !== lt2.subtags.privateUse[i].toLowerCase()) {
|
|
198
|
+
return tagSimilarity.variant;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return tagSimilarity.exact;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=similarity.js.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import * as Iana from '../../iana';
|
|
23
|
+
import { allSucceed, fail, mapResults, populateObject, succeed } from '@fgv/ts-utils';
|
|
24
|
+
import { subtagsToString } from '../common';
|
|
25
|
+
/**
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export class TagNormalizerBase {
|
|
29
|
+
constructor(iana) {
|
|
30
|
+
/* c8 ignore next - dependency injection primarily for test */
|
|
31
|
+
this._iana = iana !== null && iana !== void 0 ? iana : Iana.DefaultRegistries.languageRegistries;
|
|
32
|
+
}
|
|
33
|
+
processSubtags(subtags) {
|
|
34
|
+
return populateObject({
|
|
35
|
+
primaryLanguage: () => this._processLanguage(subtags),
|
|
36
|
+
extlangs: () => this._processExtlangs(subtags),
|
|
37
|
+
script: () => this._processScript(subtags),
|
|
38
|
+
region: () => this._processRegion(subtags),
|
|
39
|
+
variants: () => this._processVariants(subtags),
|
|
40
|
+
extensions: () => this._processExtensions(subtags),
|
|
41
|
+
privateUse: () => this._processPrivateUseTags(subtags),
|
|
42
|
+
grandfathered: () => this._processGrandfatheredTags(subtags)
|
|
43
|
+
}, { suppressUndefined: true }).onSuccess((processed) => {
|
|
44
|
+
return this._postValidate(processed);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
_basicPostValidation(subtags) {
|
|
48
|
+
/* c8 ignore next 7 - any validation whatsoever catches these so should never happen in practice */
|
|
49
|
+
if (subtags.primaryLanguage === undefined &&
|
|
50
|
+
subtags.grandfathered === undefined &&
|
|
51
|
+
subtags.privateUse === undefined) {
|
|
52
|
+
return fail(`${subtagsToString(subtags)}: missing primary language subtag.`);
|
|
53
|
+
}
|
|
54
|
+
/* c8 ignore next 3 - any validation whatsoever catches these so should never happen in practice */
|
|
55
|
+
if (subtags.extlangs && subtags.extlangs.length > 3) {
|
|
56
|
+
return fail(`${subtagsToString(subtags)}: too many extlang subtags`);
|
|
57
|
+
}
|
|
58
|
+
return succeed(subtags);
|
|
59
|
+
}
|
|
60
|
+
_postValidate(subtags) {
|
|
61
|
+
return this._basicPostValidation(subtags);
|
|
62
|
+
}
|
|
63
|
+
_processExtensions(subtags) {
|
|
64
|
+
if (subtags.extensions) {
|
|
65
|
+
return mapResults(subtags.extensions.map((ex) => {
|
|
66
|
+
return populateObject({
|
|
67
|
+
singleton: () => this._processExtensionSingleton(ex.singleton),
|
|
68
|
+
value: () => this._processExtensionSubtagValue(ex.value)
|
|
69
|
+
});
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
return succeed(subtags.extensions);
|
|
73
|
+
}
|
|
74
|
+
_verifyUnique(description, items, getKey) {
|
|
75
|
+
if (items) {
|
|
76
|
+
const present = new Set();
|
|
77
|
+
return allSucceed(items.map((i) => {
|
|
78
|
+
const key = getKey(i);
|
|
79
|
+
if (present.has(key)) {
|
|
80
|
+
return fail(`${key}: duplicate ${description}`);
|
|
81
|
+
}
|
|
82
|
+
present.add(key);
|
|
83
|
+
return succeed(key);
|
|
84
|
+
}), items);
|
|
85
|
+
}
|
|
86
|
+
return succeed(items);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=baseNormalizer.js.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import * as Iana from '../../iana';
|
|
23
|
+
import * as Bcp47Subtags from '../bcp47Subtags';
|
|
24
|
+
import { mapResults, succeed } from '@fgv/ts-utils';
|
|
25
|
+
import { TagNormalizerBase } from './baseNormalizer';
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export class CanonicalNormalizer extends TagNormalizerBase {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(...arguments);
|
|
32
|
+
this.normalization = 'canonical';
|
|
33
|
+
}
|
|
34
|
+
_processLanguage(subtags) {
|
|
35
|
+
if (subtags.primaryLanguage) {
|
|
36
|
+
return this._iana.subtags.languages.toCanonical(subtags.primaryLanguage);
|
|
37
|
+
}
|
|
38
|
+
return succeed(subtags.primaryLanguage);
|
|
39
|
+
}
|
|
40
|
+
_processExtlangs(subtags) {
|
|
41
|
+
if (subtags.extlangs) {
|
|
42
|
+
return mapResults(subtags.extlangs.map((e) => this._iana.subtags.extlangs.toCanonical(e)));
|
|
43
|
+
}
|
|
44
|
+
return succeed(undefined);
|
|
45
|
+
}
|
|
46
|
+
_processScript(subtags) {
|
|
47
|
+
if (subtags.script) {
|
|
48
|
+
return this._iana.subtags.scripts.toCanonical(subtags.script);
|
|
49
|
+
}
|
|
50
|
+
return succeed(undefined);
|
|
51
|
+
}
|
|
52
|
+
_processRegion(subtags) {
|
|
53
|
+
if (subtags.region) {
|
|
54
|
+
return this._iana.subtags.regions.toCanonical(subtags.region);
|
|
55
|
+
}
|
|
56
|
+
return succeed(undefined);
|
|
57
|
+
}
|
|
58
|
+
_processVariants(subtags) {
|
|
59
|
+
if (subtags.variants) {
|
|
60
|
+
return mapResults(subtags.variants.map((v) => this._iana.subtags.variants.toCanonical(v)));
|
|
61
|
+
}
|
|
62
|
+
return succeed(undefined);
|
|
63
|
+
}
|
|
64
|
+
_processExtensionSingleton(singleton) {
|
|
65
|
+
return this._iana.extensions.extensions.toCanonical(singleton);
|
|
66
|
+
}
|
|
67
|
+
_processExtensionSubtagValue(value) {
|
|
68
|
+
return Bcp47Subtags.Validate.extensionSubtag.toCanonical(value);
|
|
69
|
+
}
|
|
70
|
+
_processPrivateUseTags(subtags) {
|
|
71
|
+
if (subtags.privateUse) {
|
|
72
|
+
const merged = subtags.privateUse.join('-');
|
|
73
|
+
return Iana.LanguageSubtags.Validate.extendedLanguageRange.toCanonical(merged).onSuccess((canon) => {
|
|
74
|
+
return succeed(canon.split('-'));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return succeed(subtags.privateUse);
|
|
78
|
+
}
|
|
79
|
+
_processGrandfatheredTags(subtags) {
|
|
80
|
+
if (subtags.grandfathered) {
|
|
81
|
+
return this._iana.subtags.grandfathered.toCanonical(subtags.grandfathered);
|
|
82
|
+
}
|
|
83
|
+
return succeed(undefined);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=canonicalNormalizer.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Ordered ranking of the degrees of normalization, from `unknown` (least
|
|
24
|
+
* normalized) to `preferred` (most normalized).
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
const normalizationRank = {
|
|
28
|
+
/**
|
|
29
|
+
* Normalization level is unknown.
|
|
30
|
+
*/
|
|
31
|
+
unknown: 0,
|
|
32
|
+
/**
|
|
33
|
+
* Not normalized.
|
|
34
|
+
*/
|
|
35
|
+
none: 0.1,
|
|
36
|
+
/**
|
|
37
|
+
* Tag and subtag case has been normalized to canonical
|
|
38
|
+
* letter case (e.g. lower-case language and upper-case
|
|
39
|
+
* region) but no other normalization has been applied.
|
|
40
|
+
*/
|
|
41
|
+
canonical: 0.9,
|
|
42
|
+
/**
|
|
43
|
+
* All tag recommendations have been applied - e.g. suppressed
|
|
44
|
+
* script is removed, deprecated or grandfathered values are
|
|
45
|
+
* replaced with preferred values.
|
|
46
|
+
*/
|
|
47
|
+
preferred: 1.0
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Determines which of two normalization ranks is most normalized.
|
|
51
|
+
* @param n1 - The first {@link TagNormalization} to be compared.
|
|
52
|
+
* @param n2 - The second {@link TagNormalization} to me compared.
|
|
53
|
+
* @returns `1` if `n1` is more normalized, `-1` if `n2` is more
|
|
54
|
+
* normalized, or `0` if they are identical.
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
export function compareNormalization(n1, n2) {
|
|
58
|
+
if (normalizationRank[n1] > normalizationRank[n2]) {
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
else if (normalizationRank[n1] < normalizationRank[n2]) {
|
|
62
|
+
return -1;
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Chooses the most normalized of two normalization ranks.
|
|
68
|
+
* @param n1 - The first {@link TagNormalization} to be compared.
|
|
69
|
+
* @param n2 - The second {@link TagNormalization} to me compared.
|
|
70
|
+
* @returns The most normalized of `n1` or `n2`.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
export function mostNormalized(n1, n2) {
|
|
74
|
+
/* c8 ignore next - hard to hit due to guards */
|
|
75
|
+
return normalizationRank[n1] > normalizationRank[n2] ? n1 : n2;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2022 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
// istanbul ignore file
|
|
23
|
+
export * from './common';
|
|
24
|
+
export { NormalizeTag } from './normalizeTag';
|
|
25
|
+
export { CanonicalNormalizer } from './canonicalNormalizer';
|
|
26
|
+
export { PreferredNormalizer } from './preferredTagNormalizer';
|
|
27
|
+
//# sourceMappingURL=index.js.map
|