summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2024-05-06 18:44:09 -0500
committersanine <sanine.not@pm.me>2024-05-06 18:44:09 -0500
commit3c5c5ef59088a96b7988652f2dfef3d8a771f464 (patch)
tree7ce091e0b738c094014bc5f298af173c589dfefe
parent83606cd57dbfdad8a1fa0eaef2ee127f7fc2ba2c (diff)
implement consonant featural selection
-rw-r--r--src/language.test.ts70
-rw-r--r--src/language.ts99
2 files changed, 134 insertions, 35 deletions
diff --git a/src/language.test.ts b/src/language.test.ts
index d3c6f23..62b03a2 100644
--- a/src/language.test.ts
+++ b/src/language.test.ts
@@ -69,3 +69,73 @@ test('fail to output impossible consonants', () => {
voice: false,
})).toBe('');
});
+
+
+test('all consonants can be selected', () => {
+ expect(lang.pickConsonants(
+ [ lang.ConsonantPlace.Bilabial ],
+ [ lang.ConsonantManner.Nasal ],
+ [ true, true ],
+ )).toEqual([
+ {
+ place: lang.ConsonantPlace.Bilabial,
+ manner: lang.ConsonantManner.Nasal,
+ voice: false,
+ },
+ {
+ place: lang.ConsonantPlace.Bilabial,
+ manner: lang.ConsonantManner.Nasal,
+ voice: true,
+ },
+ ]);
+
+ expect(lang.pickConsonants(
+ [ lang.ConsonantPlace.Labiodental ],
+ [
+ lang.ConsonantManner.Nasal,
+ lang.ConsonantManner.Plosive,
+ lang.ConsonantManner.SibilantAffricate,
+ lang.ConsonantManner.NonSibilantAffricate,
+ lang.ConsonantManner.SibilantFricative,
+ lang.ConsonantManner.NonSibilantFricative,
+ lang.ConsonantManner.Approximant,
+ lang.ConsonantManner.Tap,
+ lang.ConsonantManner.Trill,
+ lang.ConsonantManner.LateralAffricate,
+ lang.ConsonantManner.LateralFricative,
+ lang.ConsonantManner.LateralApproximant,
+ lang.ConsonantManner.LateralTap,
+ ],
+ [ true, false ],
+ )).toEqual([
+ {
+ place: lang.ConsonantPlace.Labiodental,
+ manner: lang.ConsonantManner.Nasal,
+ voice: false,
+ },
+ {
+ place: lang.ConsonantPlace.Labiodental,
+ manner: lang.ConsonantManner.Plosive,
+ voice: false,
+ },
+ {
+ place: lang.ConsonantPlace.Labiodental,
+ manner: lang.ConsonantManner.NonSibilantAffricate,
+ voice: false,
+ },
+ {
+ place: lang.ConsonantPlace.Labiodental,
+ manner: lang.ConsonantManner.NonSibilantFricative,
+ voice: false,
+ },
+ ]);
+
+
+ expect(lang.pickConsonants(
+ [ lang.ConsonantPlace.Bilabial, lang.ConsonantPlace.Alveolar ],
+ [ lang.ConsonantManner.Plosive, lang.ConsonantManner.Tap ],
+ [ true, true ],
+ ).map(lang.consonantFeaturesToIpa)).toEqual([
+ 'p', 'b', 'ⱱ̟', 't', 'd', 'ɾ̥', 'ɾ',
+ ]);
+});
diff --git a/src/language.ts b/src/language.ts
index 0721e09..c0360b8 100644
--- a/src/language.ts
+++ b/src/language.ts
@@ -1,16 +1,16 @@
export enum VowelHeight {
- Open,
- NearOpen,
- OpenMid,
- Mid,
- CloseMid,
- NearClose,
- Close,
+ Open = 'open',
+ NearOpen = 'nearOpen',
+ OpenMid = 'openMid',
+ Mid = 'mid',
+ CloseMid = 'closeMid',
+ NearClose = 'nearClose',
+ Close = 'close',
}
export enum VowelDepth {
- Front,
- Central,
- Back,
+ Front = 'front',
+ Central = 'central',
+ Back = 'back',
}
export interface VowelFeatures {
height: VowelHeight;
@@ -106,33 +106,33 @@ export function vowelFeaturesToIpa(features: VowelFeatures): string {
export enum ConsonantPlace {
- Bilabial,
- Labiodental,
- Linguolabial,
- Dental,
- Alveolar,
- Postalveolar,
- Retroflex,
- Palatal,
- Velar,
- Uvular,
- Pharyngeal,
- Glottal,
+ Bilabial = 'bilabial',
+ Labiodental = 'labiodental',
+ Linguolabial = 'labiolingual',
+ Dental = 'dental',
+ Alveolar = 'alveolar',
+ Postalveolar = 'postalveolar',
+ Retroflex = 'retroflex',
+ Palatal = 'palatal',
+ Velar = 'velar',
+ Uvular = 'uvular',
+ Pharyngeal = 'pharyngeal',
+ Glottal = 'glottal',
}
export enum ConsonantManner {
- Nasal,
- Plosive,
- SibilantAffricate,
- NonSibilantAffricate,
- SibilantFricative,
- NonSibilantFricative,
- Approximant,
- Tap,
- Trill,
- LateralAffricate,
- LateralFricative,
- LateralApproximant,
- LateralTap,
+ Nasal = 'nasal',
+ Plosive = 'plosive',
+ SibilantAffricate = 'sibilantAffricate',
+ NonSibilantAffricate = 'nonSibilantAffricate',
+ SibilantFricative = 'sibilantFricative',
+ NonSibilantFricative = 'nonSibilantFricative',
+ Approximant = 'approximant',
+ Tap = 'tap',
+ Trill = 'trill',
+ LateralAffricate = 'lateralAffricate',
+ LateralFricative = 'lateralFricative',
+ LateralApproximant = 'lateralApproximant',
+ LateralTap = 'lateralTap',
}
export interface ConsonantFeatures {
place: ConsonantPlace;
@@ -480,3 +480,32 @@ export function consonantFeaturesToIpa(features: ConsonantFeatures): string {
}
}
}
+
+
+export function isConsonantPossible(features: ConsonantFeatures): boolean {
+ return consonantFeaturesToIpa(features) !== '';
+}
+
+
+// get all of the consonants based on the features selected
+export function pickConsonants(
+ places: ConsonantPlace[],
+ manners: ConsonantManner[],
+ voicing: [boolean, boolean],
+): ConsonantFeatures[] {
+ return places.map<ConsonantFeatures[]>(
+ place => manners.map<ConsonantFeatures[]>(
+ manner => {
+ const [ unvoiced, voiced ] = voicing;
+ const result = [];
+ if (unvoiced) {
+ result.push({ place, manner, voice: false });
+ }
+ if (voiced) {
+ result.push({ place, manner, voice: true });
+ }
+ return result;
+ }
+ ).flat()
+ ).flat().filter(isConsonantPossible);
+}