bindu 2.0.2 → 2.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/ChangeLog CHANGED
@@ -1,3 +1,18 @@
1
+ 2026.10.16, v2.0.4
2
+
3
+ fix:
4
+ - d19c008 sandhi: normalise test prefixes to bindu: sandhi: <plugin>:
5
+ - 4ec54ef sandhi: add isSequenceExpression guard to prevent double-remove crash
6
+
7
+ feature:
8
+ - 5ba9ed0 apply-vriddhi: add a+ai a+au support, import VRIDDHI from pratyahara
9
+ - f76ffe2 apply-guna: add ḷ and ā prior-vowel support via pratyahara
10
+
11
+ 2026.10.15, v2.0.3
12
+
13
+ feature:
14
+ - c7f8854 sandhi: ac: apply-dirgha: improve
15
+
1
16
  2026.10.15, v2.0.2
2
17
 
3
18
  feature:
package/lib/pratyahara.js CHANGED
@@ -14,6 +14,38 @@ const ac = [
14
14
  ...ec,
15
15
  ];
16
16
 
17
+ const ik = [
18
+ 'i',
19
+ 'I',
20
+ 'u',
21
+ 'U',
22
+ 'f',
23
+ 'F',
24
+ 'x',
25
+ ];
26
+
27
+ const en = [
28
+ 'e',
29
+ 'o',
30
+ ];
31
+
32
+ const EN = [
33
+ 'E',
34
+ 'O',
35
+ ];
36
+
37
+ const ak = [
38
+ 'a',
39
+ 'A',
40
+ 'i',
41
+ 'I',
42
+ 'u',
43
+ 'U',
44
+ 'f',
45
+ 'F',
46
+ 'x',
47
+ ];
48
+
17
49
  const khar = [
18
50
  'k',
19
51
  'c',
@@ -26,6 +58,49 @@ const khar = [
26
58
 
27
59
  const createAsti = (a) => (b) => a.includes(b.toLowerCase());
28
60
 
61
+ export const GUNA = {
62
+ i: 'e',
63
+ I: 'e',
64
+ u: 'o',
65
+ U: 'o',
66
+ f: 'ar',
67
+ F: 'ar',
68
+ x: 'al',
69
+ };
70
+
71
+ export const VRIDDHI = {
72
+ e: 'E',
73
+ o: 'O',
74
+ E: 'E',
75
+ O: 'O',
76
+ };
77
+
78
+ export const YAN_MAP = {
79
+ i: 'y',
80
+ I: 'y',
81
+ u: 'v',
82
+ U: 'v',
83
+ f: 'r',
84
+ F: 'r',
85
+ x: 'l',
86
+ };
87
+
88
+ export const DIRGHA_MAP = {
89
+ a: 'A',
90
+ A: 'A',
91
+ i: 'I',
92
+ I: 'I',
93
+ u: 'U',
94
+ U: 'U',
95
+ f: 'F',
96
+ F: 'F',
97
+ x: 'x',
98
+ };
99
+
29
100
  export const astiAc = createAsti(ac);
30
101
  export const astiEc = createAsti(ec);
31
102
  export const astiKhar = createAsti(khar);
103
+ export const astiIk = createAsti(ik);
104
+ export const astiEn = createAsti(en);
105
+ export const astiEN = createAsti(EN);
106
+ export const astiAk = createAsti(ak);
@@ -1,4 +1,5 @@
1
1
  import {operator} from 'putout';
2
+ import {astiEc} from '#pratyahara';
2
3
  import {avagraha} from '../../../symbols.js';
3
4
 
4
5
  const {remove} = operator;
@@ -38,13 +39,19 @@ export const traverse = ({push}) => ({
38
39
  Identifier(path) {
39
40
  const next = path.getNextSibling();
40
41
 
42
+ if (!path.parentPath.isSequenceExpression())
43
+ return;
44
+
41
45
  if (!next.node)
42
46
  return;
43
47
 
44
48
  const {name} = path.node;
45
49
  const nextName = next.node.name;
46
50
 
47
- if (!/([eo]|a[iu])$/.test(name))
51
+ const last = name.at(-1);
52
+ const preLast = name.at(-2);
53
+
54
+ if (!astiEc(last) && !astiEc(preLast + last))
48
55
  return;
49
56
 
50
57
  if (name.endsWith('e') && !/^[aueio]/.test(nextName))
@@ -1,12 +1,13 @@
1
1
  import {operator} from 'putout';
2
2
  import {avyayamAsti} from '#avyaya';
3
+ import {astiAk} from '#pratyahara';
3
4
 
4
5
  const {remove} = operator;
5
6
 
6
7
  export const report = () => `akaḥ savarṇe dīrghaḥ`;
7
8
 
8
9
  export const fix = ({path, next, name, nextName, dirgha}) => {
9
- path.node.name = `${name.slice(0, -1)}${dirgha}${nextName.slice(-1)}`;
10
+ path.node.name = `${name.slice(0, -1)}${dirgha}${nextName.slice(1)}`;
10
11
  remove(next);
11
12
  };
12
13
 
@@ -14,6 +15,9 @@ export const traverse = ({push}) => ({
14
15
  Identifier(path) {
15
16
  const next = path.getNextSibling();
16
17
 
18
+ if (!path.parentPath.isSequenceExpression())
19
+ return;
20
+
17
21
  if (!next.node)
18
22
  return;
19
23
 
@@ -31,6 +35,9 @@ export const traverse = ({push}) => ({
31
35
  .at(0)
32
36
  .toLowerCase();
33
37
 
38
+ if (!astiAk(last))
39
+ return;
40
+
34
41
  if (last !== first)
35
42
  return;
36
43
 
@@ -1,5 +1,5 @@
1
1
  import {operator} from 'putout';
2
- import {astiAc, astiEc} from '../../../pratyahara.js';
2
+ import {astiEc, astiAc} from '#pratyahara';
3
3
  import {praptaPratapadika} from '../../../pratipadika.js';
4
4
 
5
5
  const {remove} = operator;
@@ -40,6 +40,9 @@ export const traverse = ({push}) => ({
40
40
  Identifier(path) {
41
41
  const next = path.getNextSibling();
42
42
 
43
+ if (!path.parentPath.isSequenceExpression())
44
+ return;
45
+
43
46
  if (!next.node)
44
47
  return;
45
48
 
@@ -1,13 +1,7 @@
1
1
  import {operator} from 'putout';
2
+ import {GUNA, astiIk} from '#pratyahara';
2
3
 
3
4
  const {remove} = operator;
4
- const SANDHI = {
5
- i: 'e',
6
- u: 'o',
7
- f: 'ar',
8
- };
9
-
10
- const isSandhiVowel = (c) => Object.hasOwn(SANDHI, c);
11
5
 
12
6
  export const report = () => `ād‑guṇaḥ`;
13
7
 
@@ -20,24 +14,26 @@ export const traverse = ({push}) => ({
20
14
  Identifier(path) {
21
15
  const next = path.getNextSibling();
22
16
 
17
+ if (!path.parentPath.isSequenceExpression())
18
+ return;
19
+
23
20
  if (!next.node)
24
21
  return;
25
22
 
26
23
  const {name} = path.node;
27
24
  const nextName = next.node.name;
28
25
 
29
- const last = name
30
- .at(-1)
31
- .toLowerCase();
26
+ const last = name.at(-1);
27
+
28
+ const first = nextName.at(0);
32
29
 
33
- const first = nextName
34
- .at(0)
35
- .toLowerCase();
30
+ if (last !== 'a' && last !== 'A')
31
+ return;
36
32
 
37
- if (last !== 'a' || !isSandhiVowel(first))
33
+ if (!astiIk(first))
38
34
  return;
39
35
 
40
- const guna = SANDHI[first];
36
+ const guna = GUNA[first];
41
37
 
42
38
  push({
43
39
  path,
@@ -1,27 +1,8 @@
1
1
  import {avyayamAsti} from '#avyaya';
2
+ import {DIRGHA_MAP, YAN_MAP} from '#pratyahara';
2
3
 
3
4
  export const report = () => `ekaḥ pūrvaparayoḥ`;
4
5
 
5
- const DIRGHA = {
6
- a: 'A',
7
- A: 'A',
8
- i: 'I',
9
- I: 'I',
10
- u: 'U',
11
- U: 'U',
12
- f: 'F',
13
- x: 'X',
14
- };
15
-
16
- const YAN = {
17
- i: 'y',
18
- I: 'y',
19
- u: 'v',
20
- U: 'v',
21
- f: 'r',
22
- x: 'l',
23
- };
24
-
25
6
  export const fix = ({path, name, nextName, kind, yan, dirgha}) => {
26
7
  if (kind === 'dirgha') {
27
8
  path.node.name = `${name.slice(0, -1)}${dirgha}${nextName.slice(1)}`;
@@ -64,26 +45,26 @@ export const traverse = ({push}) => ({
64
45
  if (!/[aiufxAIU]/.test(last))
65
46
  return;
66
47
 
67
- if (lastLow === first && DIRGHA[last]) {
48
+ if (lastLow === first && DIRGHA_MAP[last]) {
68
49
  push({
69
50
  path,
70
51
  next,
71
52
  name,
72
53
  nextName,
73
54
  kind: 'dirgha',
74
- dirgha: DIRGHA[last],
55
+ dirgha: DIRGHA_MAP[last],
75
56
  });
76
57
  return;
77
58
  }
78
59
 
79
- if (YAN[last] && /[aie]/.test(first)) {
60
+ if (YAN_MAP[last] && /[aie]/.test(first)) {
80
61
  push({
81
62
  path,
82
63
  next,
83
64
  name,
84
65
  nextName,
85
66
  kind: 'yan',
86
- yan: YAN[last],
67
+ yan: YAN_MAP[last],
87
68
  });
88
69
  return;
89
70
  }
@@ -1,11 +1,24 @@
1
1
  import {operator} from 'putout';
2
+ import {
3
+ VRIDDHI,
4
+ astiEn,
5
+ astiEN,
6
+ } from '#pratyahara';
2
7
 
3
8
  const {remove} = operator;
4
9
 
5
10
  export const report = () => `vṛddhireci`;
6
11
 
7
12
  export const fix = ({path, next, name, nextName}) => {
8
- const joint = getJoint(nextName);
13
+ const first = nextName.at(0);
14
+ let joint;
15
+
16
+ if (first === 'e')
17
+ joint = 'i';
18
+ else if (first === 'o')
19
+ joint = 'u';
20
+ else
21
+ joint = VRIDDHI[first] || '';
9
22
 
10
23
  path.node.name = `${name}${joint}${nextName.slice(1)}`;
11
24
  remove(next);
@@ -24,16 +37,14 @@ export const traverse = ({push}) => ({
24
37
  const {name} = path.node;
25
38
  const nextName = next.node.name;
26
39
 
27
- const last = name
28
- .at(-1)
29
- .toLowerCase();
40
+ const last = name.at(-1);
30
41
 
31
- const [first] = nextName;
42
+ const first = nextName.at(0);
32
43
 
33
- if (last !== 'a')
44
+ if (last !== 'a' && last !== 'A')
34
45
  return;
35
46
 
36
- if (!/[oe]/.test(first) && !/^a[iu]/.test(nextName))
47
+ if (!astiEn(first) && !astiEN(first) && !/^a[iu]/.test(nextName))
37
48
  return;
38
49
 
39
50
  push({
@@ -44,16 +55,3 @@ export const traverse = ({push}) => ({
44
55
  });
45
56
  },
46
57
  });
47
-
48
- function getJoint([first, second]) {
49
- if (first === 'e')
50
- return 'i';
51
-
52
- if (second === 'i')
53
- return '';
54
-
55
- if (second === 'u')
56
- return '';
57
-
58
- return 'u';
59
- }
@@ -1,26 +1,11 @@
1
1
  import {operator} from 'putout';
2
+ import {
3
+ YAN_MAP,
4
+ astiIk,
5
+ astiAc,
6
+ } from '#pratyahara';
2
7
 
3
8
  const {remove} = operator;
4
- const {keys} = Object;
5
-
6
- const SANDHI = {
7
- i: 'y',
8
- u: 'v',
9
- f: 'r',
10
- x: 'l',
11
- };
12
-
13
- const YAN = keys(SANDHI);
14
-
15
- const SVARA = [
16
- 'a',
17
- 'i',
18
- 'u',
19
- 'f',
20
- 'x',
21
- 'e',
22
- 'o',
23
- ];
24
9
 
25
10
  export const report = () => `iko yaṇaci`;
26
11
 
@@ -34,27 +19,25 @@ export const traverse = ({push}) => ({
34
19
  Identifier(path) {
35
20
  const next = path.getNextSibling();
36
21
 
22
+ if (!path.parentPath.isSequenceExpression())
23
+ return;
24
+
37
25
  if (!next.node)
38
26
  return;
39
27
 
40
28
  const {name} = path.node;
41
29
  const nextName = next.node.name;
42
30
 
43
- const last = name
44
- .at(-1)
45
- .toLowerCase();
31
+ const last = name.at(-1);
46
32
 
47
33
  const first = nextName
48
34
  .at(0)
49
35
  .toLowerCase();
50
36
 
51
- if (!SVARA.includes(first))
52
- return;
53
-
54
- if (!YAN.includes(last))
37
+ if (!astiIk(last) || !astiAc(first))
55
38
  return;
56
39
 
57
- const yan = SANDHI[last];
40
+ const yan = YAN_MAP[last];
58
41
 
59
42
  push({
60
43
  path,
@@ -20,6 +20,9 @@ export const traverse = ({push}) => ({
20
20
  Identifier(path) {
21
21
  const next = path.getNextSibling();
22
22
 
23
+ if (!path.parentPath.isSequenceExpression())
24
+ return;
25
+
23
26
  if (!next.node)
24
27
  return;
25
28
 
@@ -10,6 +10,9 @@ export const traverse = ({push}) => ({
10
10
  Identifier(path) {
11
11
  const next = path.getNextSibling();
12
12
 
13
+ if (!path.parentPath.isSequenceExpression())
14
+ return;
15
+
13
16
  if (!next.node)
14
17
  return;
15
18
 
@@ -14,6 +14,9 @@ export const traverse = ({push}) => ({
14
14
  Identifier(path) {
15
15
  const next = path.getNextSibling();
16
16
 
17
+ if (!path.parentPath.isSequenceExpression())
18
+ return;
19
+
17
20
  if (!next.node)
18
21
  return;
19
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bindu",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Pāṇini Aṣṭādhyāyī",
5
5
  "main": "lib/bindu.js",
6
6
  "bin": {
@@ -39,7 +39,8 @@
39
39
  "node": ">=22"
40
40
  },
41
41
  "imports": {
42
- "#avyaya": "./lib/avyaya/index.js"
42
+ "#avyaya": "./lib/avyaya/index.js",
43
+ "#pratyahara": "./lib/pratyahara.js"
43
44
  },
44
45
  "dependencies": {
45
46
  "@indic-transliteration/sanscript": "^1.3.3",