@fgv/ts-bcp47 5.0.0-21 → 5.0.0-23

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.
Files changed (95) hide show
  1. package/package.json +8 -8
  2. package/src/data/bcp/overrides.json +0 -20
  3. package/src/data/iana/language-subtags.json +0 -57439
  4. package/src/data/iana/language-tag-extensions.json +0 -38
  5. package/src/data/unsd/m49.json +0 -3723
  6. package/src/index.ts +0 -29
  7. package/src/packlets/bcp47/bcp47Subtags/converters.ts +0 -33
  8. package/src/packlets/bcp47/bcp47Subtags/index.ts +0 -27
  9. package/src/packlets/bcp47/bcp47Subtags/model.ts +0 -46
  10. package/src/packlets/bcp47/bcp47Subtags/validate.ts +0 -55
  11. package/src/packlets/bcp47/common.ts +0 -85
  12. package/src/packlets/bcp47/helpers.ts +0 -117
  13. package/src/packlets/bcp47/index.ts +0 -38
  14. package/src/packlets/bcp47/languageRegistryData.ts +0 -304
  15. package/src/packlets/bcp47/languageTag.ts +0 -467
  16. package/src/packlets/bcp47/languageTagParser.ts +0 -307
  17. package/src/packlets/bcp47/match/chooser.ts +0 -164
  18. package/src/packlets/bcp47/match/common.ts +0 -57
  19. package/src/packlets/bcp47/match/index.ts +0 -26
  20. package/src/packlets/bcp47/match/similarity.ts +0 -243
  21. package/src/packlets/bcp47/normalization/baseNormalizer.ts +0 -146
  22. package/src/packlets/bcp47/normalization/canonicalNormalizer.ts +0 -102
  23. package/src/packlets/bcp47/normalization/common.ts +0 -84
  24. package/src/packlets/bcp47/normalization/index.ts +0 -27
  25. package/src/packlets/bcp47/normalization/normalizeTag.ts +0 -116
  26. package/src/packlets/bcp47/normalization/preferredTagNormalizer.ts +0 -213
  27. package/src/packlets/bcp47/overrides/converters.ts +0 -58
  28. package/src/packlets/bcp47/overrides/defaultRegistries.ts +0 -40
  29. package/src/packlets/bcp47/overrides/index.ts +0 -25
  30. package/src/packlets/bcp47/overrides/model.ts +0 -33
  31. package/src/packlets/bcp47/overrides/overridesRegistry.ts +0 -104
  32. package/src/packlets/bcp47/validation/baseValidator.ts +0 -132
  33. package/src/packlets/bcp47/validation/common.ts +0 -86
  34. package/src/packlets/bcp47/validation/index.ts +0 -29
  35. package/src/packlets/bcp47/validation/isCanonical.ts +0 -103
  36. package/src/packlets/bcp47/validation/isInPreferredForm.ts +0 -53
  37. package/src/packlets/bcp47/validation/isStrictlyValid.ts +0 -117
  38. package/src/packlets/bcp47/validation/isValid.ts +0 -122
  39. package/src/packlets/bcp47/validation/isWellFormed.ts +0 -102
  40. package/src/packlets/bcp47/validation/validateTag.ts +0 -175
  41. package/src/packlets/iana/common/converters.ts +0 -67
  42. package/src/packlets/iana/common/model.ts +0 -56
  43. package/src/packlets/iana/common/registeredItems.ts +0 -145
  44. package/src/packlets/iana/common/utils.ts +0 -32
  45. package/src/packlets/iana/common/validate.ts +0 -64
  46. package/src/packlets/iana/converters.ts +0 -26
  47. package/src/packlets/iana/defaultRegistries.ts +0 -40
  48. package/src/packlets/iana/index.ts +0 -33
  49. package/src/packlets/iana/jar/converters.ts +0 -26
  50. package/src/packlets/iana/jar/index.ts +0 -27
  51. package/src/packlets/iana/jar/jarConverters.ts +0 -70
  52. package/src/packlets/iana/jar/jarModel.ts +0 -34
  53. package/src/packlets/iana/jar/language-subtags/converters.ts +0 -26
  54. package/src/packlets/iana/jar/language-subtags/index.ts +0 -27
  55. package/src/packlets/iana/jar/language-subtags/model.ts +0 -26
  56. package/src/packlets/iana/jar/language-subtags/registry/converters.ts +0 -40
  57. package/src/packlets/iana/jar/language-subtags/registry/index.ts +0 -26
  58. package/src/packlets/iana/jar/language-subtags/registry/model.ts +0 -171
  59. package/src/packlets/iana/jar/language-subtags/tags/converters.ts +0 -120
  60. package/src/packlets/iana/jar/language-subtags/tags/index.ts +0 -28
  61. package/src/packlets/iana/jar/language-subtags/tags/model.ts +0 -71
  62. package/src/packlets/iana/jar/language-subtags/tags/tagValidation.ts +0 -67
  63. package/src/packlets/iana/jar/language-subtags/tags/validate.ts +0 -106
  64. package/src/packlets/iana/jar/model.ts +0 -26
  65. package/src/packlets/iana/language-subtags/common.ts +0 -46
  66. package/src/packlets/iana/language-subtags/converters.ts +0 -226
  67. package/src/packlets/iana/language-subtags/index.ts +0 -30
  68. package/src/packlets/iana/language-subtags/jarConverters.ts +0 -269
  69. package/src/packlets/iana/language-subtags/model.ts +0 -213
  70. package/src/packlets/iana/language-subtags/scope.ts +0 -222
  71. package/src/packlets/iana/language-subtags/subtagRegistry.ts +0 -136
  72. package/src/packlets/iana/language-subtags/validate.ts +0 -23
  73. package/src/packlets/iana/language-tag-extensions/converters.ts +0 -71
  74. package/src/packlets/iana/language-tag-extensions/extensionsRegistry.ts +0 -92
  75. package/src/packlets/iana/language-tag-extensions/extensionsScope.ts +0 -60
  76. package/src/packlets/iana/language-tag-extensions/index.ts +0 -29
  77. package/src/packlets/iana/language-tag-extensions/jarConverters.ts +0 -91
  78. package/src/packlets/iana/language-tag-extensions/model.ts +0 -67
  79. package/src/packlets/iana/language-tag-extensions/validate.ts +0 -36
  80. package/src/packlets/iana/languageRegistries.ts +0 -57
  81. package/src/packlets/iana/model.ts +0 -26
  82. package/src/packlets/iana/validate.ts +0 -23
  83. package/src/packlets/unsd/areas.ts +0 -105
  84. package/src/packlets/unsd/common.ts +0 -79
  85. package/src/packlets/unsd/csv/converters.ts +0 -82
  86. package/src/packlets/unsd/csv/index.ts +0 -26
  87. package/src/packlets/unsd/csv/model.ts +0 -44
  88. package/src/packlets/unsd/defaultRegistries.ts +0 -40
  89. package/src/packlets/unsd/index.ts +0 -28
  90. package/src/packlets/unsd/regionCodes.ts +0 -144
  91. package/src/packlets/unsd/regions.ts +0 -95
  92. package/src/packlets/utils/index.ts +0 -24
  93. package/src/packlets/utils/jsonHelpers.ts +0 -25
  94. package/src/packlets/utils/public.ts +0 -28
  95. package/src/packlets/utils/validationHelpers.ts +0 -180
@@ -1,132 +0,0 @@
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
- import * as Iana from '../../iana';
24
-
25
- import { Result, allSucceed, fail, succeed } from '@fgv/ts-utils';
26
- import { ExtensionSingleton, ExtensionSubtag } from '../bcp47Subtags/model';
27
- import { IExtensionSubtagValue, ISubtags, subtagsToString } from '../common';
28
- import { TagValidity } from './common';
29
-
30
- /**
31
- * @public
32
- */
33
- export interface ITagValidator {
34
- readonly validity: TagValidity;
35
-
36
- validateSubtags(subtags: ISubtags): Result<true>;
37
- }
38
-
39
- /**
40
- * @internal
41
- */
42
- export abstract class TagValidatorBase implements ITagValidator {
43
- public readonly iana: Iana.LanguageRegistries;
44
- public abstract readonly validity: TagValidity;
45
-
46
- public constructor(iana?: Iana.LanguageRegistries) {
47
- /* c8 ignore next */
48
- this.iana = iana ?? Iana.DefaultRegistries.languageRegistries;
49
- }
50
-
51
- public validateSubtags(subtags: ISubtags): Result<true> {
52
- return allSucceed(
53
- [
54
- this._checkLanguage(subtags),
55
- this._checkExtlangs(subtags),
56
- this._checkScript(subtags),
57
- this._checkRegion(subtags),
58
- this._checkVariants(subtags),
59
- this._checkExtensions(subtags),
60
- this._checkPrivateUseTags(subtags),
61
- this._checkGrandfatheredTags(subtags)
62
- ],
63
- true
64
- ).onSuccess(() => {
65
- return this._postValidate(subtags).onSuccess(() => succeed(true));
66
- });
67
- }
68
-
69
- protected _basicPostValidation(subtags: ISubtags): Result<ISubtags> {
70
- if (
71
- subtags.primaryLanguage === undefined &&
72
- subtags.grandfathered === undefined &&
73
- subtags.privateUse === undefined
74
- ) {
75
- return fail(`${subtagsToString(subtags)}: missing primary language subtag.`);
76
- }
77
- if (subtags.extlangs && subtags.extlangs.length > 3) {
78
- return fail(`${subtagsToString(subtags)}: too many extlang subtags`);
79
- }
80
- return succeed(subtags);
81
- }
82
-
83
- protected _postValidate(subtags: ISubtags): Result<ISubtags> {
84
- return this._basicPostValidation(subtags);
85
- }
86
-
87
- protected _checkExtensions(subtags: ISubtags): Result<IExtensionSubtagValue[] | undefined> {
88
- if (subtags.extensions) {
89
- return allSucceed(
90
- subtags.extensions.map((ext) => {
91
- return this._checkExtensionSingleton(ext.singleton).onSuccess(() => {
92
- return this._checkExtensionSubtagValue(ext.value);
93
- });
94
- }),
95
- subtags.extensions
96
- );
97
- }
98
- return succeed(undefined);
99
- }
100
-
101
- protected _verifyUnique<T, TK extends string>(
102
- description: string,
103
- items: T[] | undefined,
104
- getKey: (item: T) => TK
105
- ): Result<T[] | undefined> {
106
- if (items) {
107
- const present = new Set<TK>();
108
- return allSucceed(
109
- items.map((i) => {
110
- const key = getKey(i);
111
- if (present.has(key)) {
112
- return fail(`${key}: duplicate ${description}`);
113
- }
114
- present.add(key);
115
- return succeed(key);
116
- }),
117
- items
118
- );
119
- }
120
- return succeed(items);
121
- }
122
-
123
- protected abstract _checkLanguage(subtags: ISubtags): Result<unknown>;
124
- protected abstract _checkExtlangs(subtags: ISubtags): Result<unknown>;
125
- protected abstract _checkScript(subtags: ISubtags): Result<unknown>;
126
- protected abstract _checkRegion(subtags: ISubtags): Result<unknown>;
127
- protected abstract _checkVariants(subtags: ISubtags): Result<unknown>;
128
- protected abstract _checkExtensionSingleton(singleton: ExtensionSingleton): Result<unknown>;
129
- protected abstract _checkExtensionSubtagValue(value: ExtensionSubtag): Result<unknown>;
130
- protected abstract _checkPrivateUseTags(subtags: ISubtags): Result<unknown>;
131
- protected abstract _checkGrandfatheredTags(subtags: ISubtags): Result<unknown>;
132
- }
@@ -1,86 +0,0 @@
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
- /**
24
- * Describes the validation level of a particular tag.
25
- * @public
26
- */
27
- export type TagValidity = 'unknown' | 'well-formed' | 'valid' | 'strictly-valid';
28
-
29
- /**
30
- * Ordered ranking of the degrees of validity, from `unknown` (least
31
- * validation) to `strictly-valid` (fully validated).
32
- * @public
33
- */
34
- const validityRank: Record<TagValidity, number> = {
35
- /* eslint-disable @typescript-eslint/naming-convention */
36
- /**
37
- * No validation has been performed.
38
- */
39
- unknown: 0,
40
- /**
41
- * Tag is well-formed {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.2.9 | according to RFC 5646}.
42
- */
43
- 'well-formed': 0.5,
44
- /**
45
- * Tag is valid {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.2.9 | according to RFC 5646} -
46
- * well-formed, and is a registered grandfathered tag or all subtags are registered,
47
- * with no duplicate extensions or variant subtags.
48
- */
49
- valid: 0.9,
50
- /**
51
- * Tag is valid {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-2.2.9 | according to RFC 5646} and meets
52
- * other constraints described by the RFC - e.g. if present, any extlang or variant subtags have a
53
- * {@link https://www.rfc-editor.org/rfc/rfc5646.html#section-3.1.8 | valid prefix} as specified by
54
- * the registry.
55
- */
56
- 'strictly-valid': 1.0
57
- /* eslint-enable @typescript-eslint/naming-convention */
58
- };
59
-
60
- /**
61
- * Determines which of two validity ranks is most normalized.
62
- * @param v1 - The first {@link TagValidity} to be compared.
63
- * @param v2 - The second {@link TagValidity} to be compared.
64
- * @returns `1` if `v1` is more normalized, `-1` if `v2` is more
65
- * normalized, or `0` if they are identical.
66
- * @public
67
- */
68
- export function compareValidity(v1: TagValidity, v2: TagValidity): -1 | 0 | 1 {
69
- if (validityRank[v1] > validityRank[v2]) {
70
- return 1;
71
- } else if (validityRank[v1] < validityRank[v2]) {
72
- return -1;
73
- }
74
- return 0;
75
- }
76
-
77
- /**
78
- * Chooses the most valid of two normalization ranks.
79
- * @param v1 - The first {@link TagValidity} to be compared.
80
- * @param v2 - The second {@link TagValidity} to be compared.
81
- * @returns The most validated of `v1` or `v2`.
82
- * @public
83
- */
84
- export function mostValid(v1: TagValidity, v2: TagValidity): TagValidity {
85
- return validityRank[v1] >= validityRank[v2] ? v1 : v2;
86
- }
@@ -1,29 +0,0 @@
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
-
24
- export * from './common';
25
- export { IsCanonicalValidator } from './isCanonical';
26
- export { IsStrictlyValidValidator } from './isStrictlyValid';
27
- export { IsValidValidator } from './isValid';
28
- export { IsWellFormedValidator } from './isWellFormed';
29
- export { ValidateTag } from './validateTag';
@@ -1,103 +0,0 @@
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
- import * as Iana from '../../iana';
24
- import * as Bcp47Subtags from '../bcp47Subtags';
25
-
26
- import { Result, allSucceed, fail, succeed } from '@fgv/ts-utils';
27
- import { ExtensionSingleton, ExtensionSubtag } from '../bcp47Subtags/model';
28
-
29
- import { ISubtags } from '../common';
30
- import { TagValidatorBase } from './baseValidator';
31
- import { TagValidity } from './common';
32
-
33
- /**
34
- * @internal
35
- */
36
- export class IsCanonicalValidator extends TagValidatorBase {
37
- public validity: TagValidity = 'well-formed';
38
-
39
- protected _checkLanguage(subtags: ISubtags): Result<Iana.LanguageSubtags.LanguageSubtag | undefined> {
40
- if (subtags.primaryLanguage) {
41
- return this.iana.subtags.languages.verifyIsCanonical(subtags.primaryLanguage);
42
- }
43
- return succeed(undefined);
44
- }
45
-
46
- protected _checkExtlangs(subtags: ISubtags): Result<Iana.LanguageSubtags.ExtLangSubtag[] | undefined> {
47
- if (subtags.extlangs) {
48
- return allSucceed(
49
- subtags.extlangs.map((e) => this.iana.subtags.extlangs.verifyIsCanonical(e)),
50
- subtags.extlangs
51
- );
52
- }
53
- return succeed(undefined);
54
- }
55
-
56
- protected _checkScript(subtags: ISubtags): Result<Iana.LanguageSubtags.ScriptSubtag | undefined> {
57
- return subtags.script ? this.iana.subtags.scripts.verifyIsCanonical(subtags.script) : succeed(undefined);
58
- }
59
-
60
- protected _checkRegion(subtags: ISubtags): Result<Iana.LanguageSubtags.RegionSubtag | undefined> {
61
- return subtags.region ? this.iana.subtags.regions.verifyIsCanonical(subtags.region) : succeed(undefined);
62
- }
63
-
64
- protected _checkVariants(subtags: ISubtags): Result<Iana.LanguageSubtags.VariantSubtag[] | undefined> {
65
- if (subtags.variants) {
66
- return allSucceed(
67
- subtags.variants.map((v) => this.iana.subtags.variants.verifyIsCanonical(v)),
68
- subtags.variants
69
- );
70
- }
71
- return succeed(undefined);
72
- }
73
-
74
- protected _checkExtensionSingleton(singleton: ExtensionSingleton): Result<ExtensionSingleton> {
75
- return this.iana.extensions.extensions.verifyIsCanonical(singleton);
76
- }
77
-
78
- protected _checkExtensionSubtagValue(value: ExtensionSubtag): Result<ExtensionSubtag> {
79
- return Bcp47Subtags.Validate.extensionSubtag.verifyIsCanonical(value);
80
- }
81
-
82
- protected _checkPrivateUseTags(
83
- subtags: ISubtags
84
- ): Result<Iana.LanguageSubtags.ExtendedLanguageRange[] | undefined> {
85
- if (subtags.privateUse) {
86
- const result = Iana.LanguageSubtags.Validate.extendedLanguageRange.verifyIsCanonical(
87
- subtags.privateUse.join('-') as Iana.LanguageSubtags.ExtendedLanguageRange
88
- );
89
- if (result.isFailure()) {
90
- return fail(result.message);
91
- }
92
- }
93
- return succeed(subtags.privateUse);
94
- }
95
-
96
- protected _checkGrandfatheredTags(
97
- subtags: ISubtags
98
- ): Result<Iana.LanguageSubtags.GrandfatheredTag | undefined> {
99
- return subtags.grandfathered
100
- ? this.iana.subtags.grandfathered.verifyIsCanonical(subtags.grandfathered)
101
- : succeed(undefined);
102
- }
103
- }
@@ -1,53 +0,0 @@
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
- import * as Iana from '../../iana';
24
-
25
- import { Result, fail, succeed } from '@fgv/ts-utils';
26
- import { ISubtags, subtagsToString } from '../common';
27
- import { NormalizeTag } from '../normalization';
28
- import { ITagValidator } from './baseValidator';
29
- import { TagValidity } from './common';
30
-
31
- /**
32
- * @internal
33
- */
34
- export class IsInPreferredFromValidator implements ITagValidator {
35
- public readonly iana: Iana.LanguageRegistries;
36
- public readonly validity: TagValidity = 'valid';
37
-
38
- public constructor(iana?: Iana.LanguageRegistries) {
39
- /* c8 ignore next */
40
- this.iana = iana ?? Iana.DefaultRegistries.languageRegistries;
41
- }
42
-
43
- public validateSubtags(subtags: ISubtags): Result<true> {
44
- return NormalizeTag.toPreferred(subtags).onSuccess((preferred) => {
45
- const want = subtagsToString(preferred);
46
- const have = subtagsToString(subtags);
47
- if (want !== have) {
48
- return fail(`${have}: does not match preferred form ${want}`);
49
- }
50
- return succeed(true);
51
- });
52
- }
53
- }
@@ -1,117 +0,0 @@
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
- import * as Iana from '../../iana';
24
-
25
- import { Result, fail, mapResults, succeed } from '@fgv/ts-utils';
26
- import { ISubtags, subtagsToString } from '../common';
27
- import { NormalizeTag, TagNormalization } from '../normalization';
28
-
29
- import { TagValidity } from './common';
30
- import { IsValidValidator } from './isValid';
31
-
32
- /**
33
- * @internal
34
- */
35
- export class IsStrictlyValidValidator extends IsValidValidator {
36
- public validity: TagValidity = 'strictly-valid';
37
- public normalization: TagNormalization = 'unknown';
38
-
39
- protected _checkExtlangs(subtags: ISubtags): Result<Iana.LanguageSubtags.ExtLangSubtag[] | undefined> {
40
- if (subtags.extlangs) {
41
- return super._checkExtlangs(subtags).onSuccess(() => this._validateExtlangPrefix(subtags));
42
- }
43
- return succeed(undefined);
44
- }
45
-
46
- protected _checkVariants(subtags: ISubtags): Result<Iana.LanguageSubtags.VariantSubtag[] | undefined> {
47
- if (subtags.variants) {
48
- return super._checkVariants(subtags).onSuccess((v) => this._validateVariantPrefix(subtags, v!));
49
- }
50
- return succeed(undefined);
51
- }
52
-
53
- protected _validateExtlangPrefix(
54
- subtags: Readonly<ISubtags>
55
- ): Result<Iana.LanguageSubtags.ExtLangSubtag[] | undefined> {
56
- if (subtags.extlangs) {
57
- const prefix = this.iana.subtags.languages.toCanonical(subtags.primaryLanguage).orDefault();
58
- if (!prefix) {
59
- return fail('missing primary language for extlang prefix validation.');
60
- }
61
-
62
- return mapResults(
63
- subtags.extlangs.map((extlang) => {
64
- const def = this.iana.subtags.extlangs.tryGet(extlang);
65
- /* c8 ignore next 3 - should never happen due to guards earlier in conversion */
66
- if (!def) {
67
- return fail(`invalid extlang subtag "${extlang}" (not registered).`);
68
- }
69
- if (prefix !== def.prefix) {
70
- return fail(
71
- `invalid prefix "${prefix}" for extlang subtag ${extlang} (expected "${def.prefix}").`
72
- );
73
- }
74
- return succeed(extlang);
75
- })
76
- );
77
- }
78
- /* c8 ignore next 2 - should be caught in the caller */
79
- return succeed(undefined);
80
- }
81
-
82
- protected _validateVariantPrefix(
83
- subtags: Readonly<ISubtags>,
84
- variants: Iana.LanguageSubtags.VariantSubtag[]
85
- ): Result<Iana.LanguageSubtags.VariantSubtag[] | undefined> {
86
- const { primaryLanguage, extlangs, script, region } = subtags;
87
- const nonCanonical = { primaryLanguage, extlangs, script, region };
88
- const canonical = NormalizeTag.normalizeSubtags(nonCanonical, 'canonical');
89
- /* c8 ignore next 3 - should be caught in the first pass */
90
- if (canonical.isFailure()) {
91
- return fail(`failed to normalize variant prefix: ${canonical.message}`);
92
- }
93
- let prefix = subtagsToString(canonical.value);
94
-
95
- return mapResults(
96
- variants.map((variant) => {
97
- const def = this.iana.subtags.variants.tryGet(variant);
98
- /* c8 ignore next 3 - should be caught in the first pass */
99
- if (!def) {
100
- return fail(`invalid variant subtag "${variant}" (not registered).`);
101
- }
102
-
103
- // only fail if registration specifies prefixes but none are present
104
- if (def.prefix?.includes(prefix as Iana.LanguageSubtags.ExtendedLanguageRange) === false) {
105
- return fail(
106
- `invalid prefix "${prefix}" for variant subtag ${variant} (expected "(${def.prefix.join(
107
- ', '
108
- )})").`
109
- );
110
- }
111
- const canonicalVariant = this.iana.subtags.variants.toCanonical(variant).orDefault();
112
- prefix = `${prefix}-${canonicalVariant}`;
113
- return succeed(variant);
114
- })
115
- );
116
- }
117
- }
@@ -1,122 +0,0 @@
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
- import * as Iana from '../../iana';
24
- import * as Bcp47Subtags from '../bcp47Subtags';
25
-
26
- import { Result, allSucceed, fail, mapResults, succeed } from '@fgv/ts-utils';
27
- import { ExtensionSingleton, ExtensionSubtag } from '../bcp47Subtags/model';
28
- import { IExtensionSubtagValue, ISubtags } from '../common';
29
- import { TagValidatorBase } from './baseValidator';
30
- import { TagValidity } from './common';
31
-
32
- /**
33
- * @internal
34
- */
35
- export class IsValidValidator extends TagValidatorBase {
36
- public validity: TagValidity = 'valid';
37
-
38
- protected _checkLanguage(subtags: ISubtags): Result<Iana.LanguageSubtags.LanguageSubtag | undefined> {
39
- return subtags.primaryLanguage
40
- ? this.iana.subtags.languages.verifyIsValid(subtags.primaryLanguage)
41
- : succeed(undefined);
42
- }
43
-
44
- protected _checkExtlangs(subtags: ISubtags): Result<Iana.LanguageSubtags.ExtLangSubtag[] | undefined> {
45
- if (subtags.extlangs) {
46
- return allSucceed(
47
- subtags.extlangs.map((e) => this.iana.subtags.extlangs.verifyIsValid(e)),
48
- subtags.extlangs
49
- );
50
- }
51
- return succeed(undefined);
52
- }
53
-
54
- protected _checkScript(subtags: ISubtags): Result<Iana.LanguageSubtags.ScriptSubtag | undefined> {
55
- return subtags.script ? this.iana.subtags.scripts.verifyIsValid(subtags.script) : succeed(undefined);
56
- }
57
-
58
- protected _checkRegion(subtags: ISubtags): Result<Iana.LanguageSubtags.RegionSubtag | undefined> {
59
- return subtags.region ? this.iana.subtags.regions.verifyIsValid(subtags.region) : succeed(undefined);
60
- }
61
-
62
- protected _checkVariants(subtags: ISubtags): Result<Iana.LanguageSubtags.VariantSubtag[] | undefined> {
63
- if (subtags.variants) {
64
- return allSucceed(
65
- subtags.variants.map((v) => this.iana.subtags.variants.verifyIsValid(v)),
66
- subtags.variants
67
- ).onSuccess((v) => {
68
- return mapResults(v.map((vc) => this.iana.subtags.variants.toCanonical(vc))).onSuccess(
69
- (canonical) => {
70
- return this._verifyUnique('variant subtag', canonical, (v) => v);
71
- }
72
- );
73
- });
74
- }
75
- return succeed(undefined);
76
- }
77
-
78
- protected _checkExtensionSingleton(singleton: ExtensionSingleton): Result<ExtensionSingleton> {
79
- return this.iana.extensions.extensions.verifyIsValid(singleton);
80
- }
81
-
82
- protected _checkExtensionSubtagValue(value: ExtensionSubtag): Result<ExtensionSubtag> {
83
- return Bcp47Subtags.Validate.extensionSubtag.verifyIsWellFormed(value);
84
- }
85
-
86
- protected _checkExtensions(subtags: ISubtags): Result<IExtensionSubtagValue[] | undefined> {
87
- return super._checkExtensions(subtags).onSuccess((extensions) => {
88
- return this._verifyUnique('extensions', extensions, (e) => e.singleton.toLowerCase());
89
- });
90
- }
91
-
92
- protected _checkPrivateUseTags(
93
- subtags: ISubtags
94
- ): Result<Iana.LanguageSubtags.ExtendedLanguageRange[] | undefined> {
95
- if (subtags.privateUse) {
96
- return allSucceed(
97
- subtags.privateUse.map((pu) =>
98
- Iana.LanguageSubtags.Validate.extendedLanguageRange.verifyIsWellFormed(pu)
99
- ),
100
- subtags.privateUse
101
- );
102
- }
103
- return succeed(subtags.privateUse);
104
- }
105
-
106
- protected _checkGrandfatheredTags(
107
- subtags: ISubtags
108
- ): Result<Iana.LanguageSubtags.GrandfatheredTag | undefined> {
109
- return subtags.grandfathered
110
- ? this.iana.subtags.grandfathered.verifyIsValid(subtags.grandfathered)
111
- : succeed(undefined);
112
- }
113
-
114
- protected _postValidate(subtags: ISubtags): Result<ISubtags> {
115
- return this._basicPostValidation(subtags).onSuccess((validated) => {
116
- if (validated.extlangs && validated.extlangs.length > 1) {
117
- return fail(`${validated.extlangs.join('-')}: multiple extlang subtags is invalid`);
118
- }
119
- return succeed(validated);
120
- });
121
- }
122
- }