astro-ghostcms/.pnpm-store/v3/files/2d/8199623e7c69d49df5b615c5748...

84 lines
3.0 KiB
Plaintext
Raw Normal View History

2024-02-14 14:10:47 +00:00
/**
* Apply Arabic presentation forms to a range of tokens
*/
import { ContextParams } from '../../tokenizer';
import { isIsolatedArabicChar, isTashkeelArabicChar } from '../../char';
import { SubstitutionAction } from '../featureQuery';
import applySubstitution from '../applySubstitution';
/**
* Check if a char can be connected to it's preceding char
* @param {ContextParams} charContextParams context params of a char
*/
function willConnectPrev(charContextParams) {
let backtrack = [].concat(charContextParams.backtrack);
for (let i = backtrack.length - 1; i >= 0; i--) {
const prevChar = backtrack[i];
const isolated = isIsolatedArabicChar(prevChar);
const tashkeel = isTashkeelArabicChar(prevChar);
if (!isolated && !tashkeel) return true;
if (isolated) return false;
}
return false;
}
/**
* Check if a char can be connected to it's proceeding char
* @param {ContextParams} charContextParams context params of a char
*/
function willConnectNext(charContextParams) {
if (isIsolatedArabicChar(charContextParams.current)) return false;
for (let i = 0; i < charContextParams.lookahead.length; i++) {
const nextChar = charContextParams.lookahead[i];
const tashkeel = isTashkeelArabicChar(nextChar);
if (!tashkeel) return true;
}
return false;
}
/**
* Apply arabic presentation forms to a list of tokens
* @param {ContextRange} range a range of tokens
*/
function arabicPresentationForms(range) {
const script = 'arab';
const tags = this.featuresTags[script];
const tokens = this.tokenizer.getRangeTokens(range);
if (tokens.length === 1) return;
let contextParams = new ContextParams(
tokens.map(token => token.getState('glyphIndex')
), 0);
const charContextParams = new ContextParams(
tokens.map(token => token.char
), 0);
tokens.forEach((token, index) => {
if (isTashkeelArabicChar(token.char)) return;
contextParams.setCurrentIndex(index);
charContextParams.setCurrentIndex(index);
let CONNECT = 0; // 2 bits 00 (10: can connect next) (01: can connect prev)
if (willConnectPrev(charContextParams)) CONNECT |= 1;
if (willConnectNext(charContextParams)) CONNECT |= 2;
let tag;
switch (CONNECT) {
case 1: (tag = 'fina'); break;
case 2: (tag = 'init'); break;
case 3: (tag = 'medi'); break;
}
if (tags.indexOf(tag) === -1) return;
let substitutions = this.query.lookupFeature({
tag, script, contextParams
});
if (substitutions instanceof Error) return console.info(substitutions.message);
substitutions.forEach((action, index) => {
if (action instanceof SubstitutionAction) {
applySubstitution(action, tokens, index);
contextParams.context[index] = action.substitution;
}
});
});
}
export default arabicPresentationForms;
export { arabicPresentationForms };