skrits 1.0.0

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 (58) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/CODE_OF_CONDUCT.md +87 -0
  3. package/CONTRIBUTING.md +62 -0
  4. package/README.md +145 -0
  5. package/SECURITY.md +25 -0
  6. package/SUPPORT.md +13 -0
  7. package/dist/core/caseHelper.d.ts +5 -0
  8. package/dist/core/caseHelper.d.ts.map +1 -0
  9. package/dist/core/caseHelper.js +37 -0
  10. package/dist/core/index.d.ts +5 -0
  11. package/dist/core/index.d.ts.map +1 -0
  12. package/dist/core/index.js +21 -0
  13. package/dist/core/stringUtils.d.ts +9 -0
  14. package/dist/core/stringUtils.d.ts.map +1 -0
  15. package/dist/core/stringUtils.js +28 -0
  16. package/dist/core/tokenizer.d.ts +4 -0
  17. package/dist/core/tokenizer.d.ts.map +1 -0
  18. package/dist/core/tokenizer.js +15 -0
  19. package/dist/core/transliteration.d.ts +8 -0
  20. package/dist/core/transliteration.d.ts.map +1 -0
  21. package/dist/core/transliteration.js +85 -0
  22. package/dist/index.d.ts +10 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +47 -0
  25. package/dist/leet.d.ts +25 -0
  26. package/dist/leet.d.ts.map +1 -0
  27. package/dist/leet.js +108 -0
  28. package/dist/leetrovacki.d.ts +37 -0
  29. package/dist/leetrovacki.d.ts.map +1 -0
  30. package/dist/leetrovacki.js +109 -0
  31. package/dist/satrovacki.d.ts +25 -0
  32. package/dist/satrovacki.d.ts.map +1 -0
  33. package/dist/satrovacki.js +157 -0
  34. package/dist/skrit.d.ts +28 -0
  35. package/dist/skrit.d.ts.map +1 -0
  36. package/dist/skrit.js +167 -0
  37. package/dist/utrovacki.d.ts +19 -0
  38. package/dist/utrovacki.d.ts.map +1 -0
  39. package/dist/utrovacki.js +100 -0
  40. package/package.json +32 -0
  41. package/src/core/caseHelper.ts +31 -0
  42. package/src/core/index.ts +4 -0
  43. package/src/core/stringUtils.ts +25 -0
  44. package/src/core/tokenizer.ts +12 -0
  45. package/src/core/transliteration.ts +84 -0
  46. package/src/index.ts +34 -0
  47. package/src/leet.ts +118 -0
  48. package/src/leetrovacki.ts +141 -0
  49. package/src/satrovacki.ts +176 -0
  50. package/src/skrit.ts +188 -0
  51. package/src/utrovacki.ts +111 -0
  52. package/tests/leet.test.ts +117 -0
  53. package/tests/leetrovacki.test.ts +76 -0
  54. package/tests/satrovacki.test.ts +112 -0
  55. package/tests/skrit.test.ts +80 -0
  56. package/tests/transliteration.test.ts +64 -0
  57. package/tests/utrovacki.test.ts +83 -0
  58. package/tsconfig.json +17 -0
package/dist/index.js ADDED
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ // src/index.ts - Main entry point
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports._looksLikeSatroEncoded = exports._deleetTextBasic = exports.detectLeetBase = exports.detectMode = exports.encodeText = exports.looksLikeLeet = exports.applyLeet = exports.buildFullLeetProfile = exports.getLeetProfile = exports.availableProfiles = exports.LeetEncoder = exports.LEET_SIGNAL_CHARS = exports.DEFAULT_LEET_DENSITY = exports.READABLE_FULL_PROFILE = exports.BASIC_LEET_PROFILE = exports.LEET_TABLE = exports.Leetrovacki = exports.Utrovacki = exports.Satrovacki = void 0;
19
+ var satrovacki_1 = require("./satrovacki");
20
+ Object.defineProperty(exports, "Satrovacki", { enumerable: true, get: function () { return satrovacki_1.Satrovacki; } });
21
+ var utrovacki_1 = require("./utrovacki");
22
+ Object.defineProperty(exports, "Utrovacki", { enumerable: true, get: function () { return utrovacki_1.Utrovacki; } });
23
+ var leetrovacki_1 = require("./leetrovacki");
24
+ Object.defineProperty(exports, "Leetrovacki", { enumerable: true, get: function () { return leetrovacki_1.Leetrovacki; } });
25
+ var leet_1 = require("./leet");
26
+ Object.defineProperty(exports, "LEET_TABLE", { enumerable: true, get: function () { return leet_1.LEET_TABLE; } });
27
+ Object.defineProperty(exports, "BASIC_LEET_PROFILE", { enumerable: true, get: function () { return leet_1.BASIC_LEET_PROFILE; } });
28
+ Object.defineProperty(exports, "READABLE_FULL_PROFILE", { enumerable: true, get: function () { return leet_1.READABLE_FULL_PROFILE; } });
29
+ Object.defineProperty(exports, "DEFAULT_LEET_DENSITY", { enumerable: true, get: function () { return leet_1.DEFAULT_LEET_DENSITY; } });
30
+ Object.defineProperty(exports, "LEET_SIGNAL_CHARS", { enumerable: true, get: function () { return leet_1.LEET_SIGNAL_CHARS; } });
31
+ Object.defineProperty(exports, "LeetEncoder", { enumerable: true, get: function () { return leet_1.LeetEncoder; } });
32
+ Object.defineProperty(exports, "availableProfiles", { enumerable: true, get: function () { return leet_1.availableProfiles; } });
33
+ Object.defineProperty(exports, "getLeetProfile", { enumerable: true, get: function () { return leet_1.getLeetProfile; } });
34
+ Object.defineProperty(exports, "buildFullLeetProfile", { enumerable: true, get: function () { return leet_1.buildFullLeetProfile; } });
35
+ Object.defineProperty(exports, "applyLeet", { enumerable: true, get: function () { return leet_1.applyLeet; } });
36
+ Object.defineProperty(exports, "looksLikeLeet", { enumerable: true, get: function () { return leet_1.looksLikeLeet; } });
37
+ var skrit_1 = require("./skrit");
38
+ Object.defineProperty(exports, "encodeText", { enumerable: true, get: function () { return skrit_1.encodeText; } });
39
+ Object.defineProperty(exports, "detectMode", { enumerable: true, get: function () { return skrit_1.detectMode; } });
40
+ Object.defineProperty(exports, "detectLeetBase", { enumerable: true, get: function () { return skrit_1.detectLeetBase; } });
41
+ Object.defineProperty(exports, "_deleetTextBasic", { enumerable: true, get: function () { return skrit_1._deleetTextBasic; } });
42
+ Object.defineProperty(exports, "_looksLikeSatroEncoded", { enumerable: true, get: function () { return skrit_1._looksLikeSatroEncoded; } });
43
+ __exportStar(require("./core/transliteration"), exports);
44
+ __exportStar(require("./core/caseHelper"), exports);
45
+ __exportStar(require("./core/stringUtils"), exports);
46
+ __exportStar(require("./core/tokenizer"), exports);
47
+ //# sourceMappingURL=index.js.map
package/dist/leet.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ export declare const LEET_TABLE: Record<string, string[]>;
2
+ export declare const BASIC_LEET_PROFILE: Record<string, string>;
3
+ export declare const READABLE_FULL_PROFILE: Record<string, string>;
4
+ export type LeetProfile = 'basic' | 'readable' | 'full';
5
+ export declare function availableProfiles(): LeetProfile[];
6
+ export declare function getLeetProfile(name: LeetProfile | string, customMap?: Record<string, string>, complexity?: number): Record<string, string>;
7
+ export declare function buildFullLeetProfile(complexity?: number): Record<string, string>;
8
+ export declare const DEFAULT_LEET_DENSITY = 0.86;
9
+ export declare const LEET_SIGNAL_CHARS: Set<string>;
10
+ export declare function applyLeet(text: string, mapping: Record<string, string>, density?: number): string;
11
+ export declare function looksLikeLeet(text: string): boolean;
12
+ export interface LeetEncoderOptions {
13
+ profile?: LeetProfile | string;
14
+ customMap?: Record<string, string>;
15
+ complexity?: number;
16
+ density?: number;
17
+ }
18
+ export declare class LeetEncoder {
19
+ readonly profile: LeetProfile | string;
20
+ readonly mapping: Record<string, string>;
21
+ readonly density: number;
22
+ constructor(options?: LeetEncoderOptions);
23
+ encode(text: string): string;
24
+ }
25
+ //# sourceMappingURL=leet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leet.d.ts","sourceRoot":"","sources":["../src/leet.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CA2B/C,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAErD,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAExD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAExD,wBAAgB,iBAAiB,IAAI,WAAW,EAAE,CAEjD;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,GAAG,MAAM,EAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,SAAI,GACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED,wBAAgB,oBAAoB,CAAC,UAAU,SAAI,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO3E;AAED,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,eAAO,MAAM,iBAAiB,aAA8D,CAAC;AAE7F,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,SAAuB,GAAG,MAAM,CAiB/G;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,OAAO,GAAE,kBAAuB;IAM5C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAG7B"}
package/dist/leet.js ADDED
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ // src/leet.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.LeetEncoder = exports.LEET_SIGNAL_CHARS = exports.DEFAULT_LEET_DENSITY = exports.READABLE_FULL_PROFILE = exports.BASIC_LEET_PROFILE = exports.LEET_TABLE = void 0;
5
+ exports.availableProfiles = availableProfiles;
6
+ exports.getLeetProfile = getLeetProfile;
7
+ exports.buildFullLeetProfile = buildFullLeetProfile;
8
+ exports.applyLeet = applyLeet;
9
+ exports.looksLikeLeet = looksLikeLeet;
10
+ exports.LEET_TABLE = {
11
+ a: ['4', '@', '/\\', 'а'],
12
+ b: ['8', '|3', '13'],
13
+ c: ['(', '<', '{', '['],
14
+ d: ['|)', 'cl', '[)'],
15
+ e: ['3', '€', '[-'],
16
+ f: ['|=', 'ph', '|#'],
17
+ g: ['6', '9', '(_+'],
18
+ h: ['#', '|-|', '}{', ')-('],
19
+ i: ['1', '!', '|', ']['],
20
+ j: ['_|', ']', '_)'],
21
+ k: ['|<', '|{', 'ik'],
22
+ l: ['1', '|_', '|'],
23
+ m: ['|\\/|', '|v|', '/\\/\\', '|\\/|'],
24
+ n: ['|\\|', '/\\/', '|\\/|', '|\\\\|'],
25
+ o: ['0', '()', '[]', '<>'],
26
+ p: ['|*', '|o', '|>', '|"'],
27
+ q: ['(,)', '0_', 'kw'],
28
+ r: ['|2', '|?', '/2', 'I2'],
29
+ s: ['5', '$', 'z'],
30
+ t: ['7', '+', '†'],
31
+ u: ['00', '|_|', '\\_/'],
32
+ v: ['\\/', '\\/'],
33
+ w: ['\\/\\/', 'vv', '\\|/', '\\^/'],
34
+ x: ['><', '%', '}{'],
35
+ y: ['`/', '¥', '\\|/'],
36
+ z: ['2', '7_', '>_'],
37
+ };
38
+ exports.BASIC_LEET_PROFILE = {
39
+ a: '4', e: '3', i: '1', o: '0', s: '5', t: '7', u: '00', z: '2',
40
+ };
41
+ exports.READABLE_FULL_PROFILE = {
42
+ a: '4', b: '8', e: '3', g: '6', i: '1', o: '0', s: '5', t: '7', z: '2',
43
+ };
44
+ function availableProfiles() {
45
+ return ['basic', 'readable', 'full'];
46
+ }
47
+ function getLeetProfile(name, customMap, complexity = 0) {
48
+ if (customMap)
49
+ return customMap;
50
+ if (name === 'basic')
51
+ return { ...exports.BASIC_LEET_PROFILE };
52
+ if (name === 'readable')
53
+ return { ...exports.READABLE_FULL_PROFILE };
54
+ if (name === 'full')
55
+ return buildFullLeetProfile(complexity);
56
+ throw new Error(`Unknown leet profile: ${name}. Available: basic, readable, full`);
57
+ }
58
+ function buildFullLeetProfile(complexity = 0) {
59
+ const result = {};
60
+ for (const [letter, variants] of Object.entries(exports.LEET_TABLE)) {
61
+ const idx = Math.min(complexity, variants.length - 1);
62
+ result[letter] = variants[idx];
63
+ }
64
+ return result;
65
+ }
66
+ exports.DEFAULT_LEET_DENSITY = 0.86;
67
+ exports.LEET_SIGNAL_CHARS = new Set(['4', '3', '1', '0', '5', '7', '2', '@', '$', '!']);
68
+ function applyLeet(text, mapping, density = exports.DEFAULT_LEET_DENSITY) {
69
+ if (density < 0 || density > 1)
70
+ throw new Error('Leet density must be between 0.0 and 1.0');
71
+ const chars = [...text];
72
+ return chars.map((ch, pos) => {
73
+ const lower = ch.toLowerCase();
74
+ const replacement = mapping[lower];
75
+ if (!replacement)
76
+ return ch;
77
+ // Density check: deterministic pseudo-random based on char value and position
78
+ const charOrd = ch.codePointAt(0) ?? 0;
79
+ const score = (pos * 131 + charOrd * 17) % 100;
80
+ if (score >= density * 100)
81
+ return ch;
82
+ // Preserve case if possible
83
+ if (ch === ch.toUpperCase() && ch !== ch.toLowerCase()) {
84
+ return replacement.toUpperCase();
85
+ }
86
+ return replacement;
87
+ }).join('');
88
+ }
89
+ function looksLikeLeet(text) {
90
+ let signalCount = 0;
91
+ for (const ch of text) {
92
+ if (exports.LEET_SIGNAL_CHARS.has(ch))
93
+ signalCount++;
94
+ }
95
+ return signalCount >= 2;
96
+ }
97
+ class LeetEncoder {
98
+ constructor(options = {}) {
99
+ this.profile = options.profile ?? 'basic';
100
+ this.density = options.density ?? exports.DEFAULT_LEET_DENSITY;
101
+ this.mapping = getLeetProfile(this.profile, options.customMap, options.complexity ?? 0);
102
+ }
103
+ encode(text) {
104
+ return applyLeet(text, this.mapping, this.density);
105
+ }
106
+ }
107
+ exports.LeetEncoder = LeetEncoder;
108
+ //# sourceMappingURL=leet.js.map
@@ -0,0 +1,37 @@
1
+ import { SatrovackiOptions } from './satrovacki';
2
+ import { LeetProfile } from './leet';
3
+ export type LeetBase = 'auto' | 'satro' | 'utro';
4
+ export type ZaStyle = '24' | 'z4';
5
+ export type NjeStyle = 'n73' | 'nj3' | 'њ';
6
+ export interface LeetrovackiOptions extends SatrovackiOptions {
7
+ base?: LeetBase;
8
+ leetProfile?: LeetProfile | string;
9
+ leetComplexity?: number;
10
+ leetDensity?: number;
11
+ zaStyle?: ZaStyle;
12
+ njeStyle?: NjeStyle;
13
+ prefix?: string;
14
+ infix?: string;
15
+ suffix?: string;
16
+ }
17
+ export declare class Leetrovacki {
18
+ readonly base: LeetBase;
19
+ readonly leetProfile: LeetProfile | string;
20
+ readonly leetComplexity: number;
21
+ readonly leetDensity: number;
22
+ readonly zaStyle: ZaStyle;
23
+ readonly njeStyle: NjeStyle;
24
+ private readonly satroCoder;
25
+ private readonly utroCoder;
26
+ private readonly leetMapping;
27
+ constructor(options?: LeetrovackiOptions);
28
+ encode(text: string): string;
29
+ encodeWord(word: string): string;
30
+ private _resolveBase;
31
+ private _looksLikeUtro;
32
+ private _leetifyUtro;
33
+ private _leetifySatro;
34
+ private _zaReplacement;
35
+ private _njeReplacement;
36
+ }
37
+ //# sourceMappingURL=leetrovacki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leetrovacki.d.ts","sourceRoot":"","sources":["../src/leetrovacki.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAmD,WAAW,EAAE,MAAM,QAAQ,CAAC;AAKtF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAClC,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;gBAEzC,OAAO,GAAE,kBAAuB;IA6B5C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAO5B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAahC,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,eAAe;CAKxB"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ // src/leetrovacki.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Leetrovacki = void 0;
5
+ const satrovacki_1 = require("./satrovacki");
6
+ const utrovacki_1 = require("./utrovacki");
7
+ const leet_1 = require("./leet");
8
+ const tokenizer_1 = require("./core/tokenizer");
9
+ const stringUtils_1 = require("./core/stringUtils");
10
+ class Leetrovacki {
11
+ constructor(options = {}) {
12
+ this.base = options.base ?? 'auto';
13
+ this.leetProfile = options.leetProfile ?? 'basic';
14
+ this.leetComplexity = options.leetComplexity ?? 0;
15
+ this.leetDensity = options.leetDensity ?? leet_1.DEFAULT_LEET_DENSITY;
16
+ this.zaStyle = options.zaStyle ?? '24';
17
+ this.njeStyle = options.njeStyle ?? 'n73';
18
+ if (this.leetDensity < 0 || this.leetDensity > 1) {
19
+ throw new Error('leet_density must be between 0.0 and 1.0');
20
+ }
21
+ const sharedOpts = {
22
+ minWordLength: options.minWordLength,
23
+ plainCTarget: options.plainCTarget,
24
+ softTjToCyrillic: options.softTjToCyrillic,
25
+ exceptions: options.exceptions,
26
+ };
27
+ this.satroCoder = new satrovacki_1.Satrovacki(sharedOpts);
28
+ this.utroCoder = new utrovacki_1.Utrovacki({
29
+ ...sharedOpts,
30
+ prefix: options.prefix,
31
+ infix: options.infix,
32
+ suffix: options.suffix,
33
+ });
34
+ this.leetMapping = (0, leet_1.getLeetProfile)(this.leetProfile, undefined, this.leetComplexity);
35
+ }
36
+ encode(text) {
37
+ return (0, tokenizer_1.tokenize)(text).map(token => {
38
+ if ((0, tokenizer_1.isAlpha)(token))
39
+ return this.encodeWord(token);
40
+ return token;
41
+ }).join('');
42
+ }
43
+ encodeWord(word) {
44
+ if ((0, stringUtils_1.strLen)(word) < (this.satroCoder.minWordLength))
45
+ return word;
46
+ const resolvedBase = this._resolveBase(word);
47
+ if (resolvedBase === 'utro') {
48
+ const utroEncoded = this.utroCoder.encodeWord(word);
49
+ return this._leetifyUtro(utroEncoded);
50
+ }
51
+ else {
52
+ const satroEncoded = this.satroCoder.encodeWord(word);
53
+ return this._leetifySatro(satroEncoded);
54
+ }
55
+ }
56
+ _resolveBase(word) {
57
+ if (this.base === 'utro')
58
+ return 'utro';
59
+ if (this.base === 'satro')
60
+ return 'satro';
61
+ // auto: check if word looks like utro encoded
62
+ if (this._looksLikeUtro(word))
63
+ return 'utro';
64
+ return 'satro';
65
+ }
66
+ _looksLikeUtro(word) {
67
+ return this.utroCoder.canDecodeWord(word);
68
+ }
69
+ _leetifyUtro(encoded) {
70
+ // In utro mode: apply leet but handle 'za' and 'nje' styling
71
+ const lower = encoded.toLowerCase();
72
+ const pre = this.utroCoder.prefix.toLowerCase();
73
+ const inf = this.utroCoder.infix.toLowerCase();
74
+ const suf = this.utroCoder.suffix.toLowerCase();
75
+ // Find the structural parts
76
+ if (lower.startsWith(pre) && lower.endsWith(suf)) {
77
+ const inner = lower.slice(pre.length, lower.length - suf.length);
78
+ const infIdx = inner.indexOf(inf);
79
+ if (infIdx !== -1) {
80
+ const part2 = inner.slice(0, infIdx);
81
+ const part1 = inner.slice(infIdx + inf.length);
82
+ const leetPart2 = (0, leet_1.applyLeet)(part2, this.leetMapping, this.leetDensity);
83
+ const leetPart1 = (0, leet_1.applyLeet)(part1, this.leetMapping, this.leetDensity);
84
+ const zaStr = this._zaReplacement();
85
+ const njeStr = this._njeReplacement();
86
+ return pre + leetPart2 + zaStr + leetPart1 + njeStr;
87
+ }
88
+ }
89
+ // Fallback: apply leet to whole thing
90
+ return (0, leet_1.applyLeet)(encoded, this.leetMapping, this.leetDensity);
91
+ }
92
+ _leetifySatro(encoded) {
93
+ return (0, leet_1.applyLeet)(encoded, this.leetMapping, this.leetDensity);
94
+ }
95
+ _zaReplacement() {
96
+ if (this.zaStyle === 'z4')
97
+ return 'z4';
98
+ return '24'; // default '24'
99
+ }
100
+ _njeReplacement() {
101
+ if (this.njeStyle === 'nj3')
102
+ return 'nj3';
103
+ if (this.njeStyle === 'њ')
104
+ return 'њ';
105
+ return 'n73'; // default
106
+ }
107
+ }
108
+ exports.Leetrovacki = Leetrovacki;
109
+ //# sourceMappingURL=leetrovacki.js.map
@@ -0,0 +1,25 @@
1
+ export interface SatrovackiOptions {
2
+ minWordLength?: number;
3
+ plainCTarget?: string;
4
+ softTjToCyrillic?: boolean;
5
+ exceptions?: Record<string, string>;
6
+ }
7
+ export declare class Satrovacki {
8
+ readonly minWordLength: number;
9
+ readonly plainCTarget: string;
10
+ readonly softTjToCyrillic: boolean;
11
+ readonly exceptions: Record<string, string>;
12
+ constructor(options?: SatrovackiOptions);
13
+ encode(text: string): string;
14
+ decode(text: string): string;
15
+ encodeWord(word: string): string;
16
+ decodeWord(word: string): string;
17
+ canDecodeWord(word: string): boolean;
18
+ _encodeLatinWord(lowerWord: string): string;
19
+ _encodeLatinWordPlain(lowerWord: string): string;
20
+ _decodeCandidates(lowerWord: string): Array<[number, string]>;
21
+ _pickBestDecodeCandidate(candidates: Array<[number, string]>): string;
22
+ protected _findSplitIndex(word: string): number;
23
+ protected _isVowelAt(word: string, i: number): boolean;
24
+ }
25
+ //# sourceMappingURL=satrovacki.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"satrovacki.d.ts","sourceRoot":"","sources":["../src/satrovacki.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAID,qBAAa,UAAU;IACrB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAEhC,OAAO,GAAE,iBAAsB;IAO3C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAO5B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAO5B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAehC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAyBhC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAcpC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAM3C,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQhD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAiB7D,wBAAwB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM;IAoBrE,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAc/C,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;CAavD"}
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ // D:\Projects\SkriTS\src\satrovacki.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Satrovacki = void 0;
5
+ const transliteration_1 = require("./core/transliteration");
6
+ const caseHelper_1 = require("./core/caseHelper");
7
+ const tokenizer_1 = require("./core/tokenizer");
8
+ const stringUtils_1 = require("./core/stringUtils");
9
+ const VOWELS = new Set(['a', 'e', 'i', 'o', 'u', 'а', 'е', 'и', 'о', 'у']);
10
+ class Satrovacki {
11
+ constructor(options = {}) {
12
+ this.minWordLength = options.minWordLength ?? 3;
13
+ this.plainCTarget = options.plainCTarget ?? 'ц';
14
+ this.softTjToCyrillic = options.softTjToCyrillic ?? false;
15
+ this.exceptions = options.exceptions ?? {};
16
+ }
17
+ encode(text) {
18
+ return (0, tokenizer_1.tokenize)(text).map(token => {
19
+ if ((0, tokenizer_1.isAlpha)(token))
20
+ return this.encodeWord(token);
21
+ return token;
22
+ }).join('');
23
+ }
24
+ decode(text) {
25
+ return (0, tokenizer_1.tokenize)(text).map(token => {
26
+ if ((0, tokenizer_1.isAlpha)(token))
27
+ return this.decodeWord(token);
28
+ return token;
29
+ }).join('');
30
+ }
31
+ encodeWord(word) {
32
+ if ((0, stringUtils_1.strLen)(word) < this.minWordLength)
33
+ return word;
34
+ const isCyr = (0, transliteration_1.containsCyrillic)(word);
35
+ const latin = isCyr ? (0, transliteration_1.cyrillicToLatin)(word) : word;
36
+ const latinLower = latin.toLowerCase();
37
+ const replaced = this._encodeLatinWord(latinLower);
38
+ let result = (0, caseHelper_1.applyCase)(latin, replaced);
39
+ if (isCyr) {
40
+ result = (0, transliteration_1.latinToCyrillic)(result, this.softTjToCyrillic, this.plainCTarget);
41
+ }
42
+ return result;
43
+ }
44
+ decodeWord(word) {
45
+ if ((0, stringUtils_1.strLen)(word) < this.minWordLength)
46
+ return word;
47
+ const isCyr = (0, transliteration_1.containsCyrillic)(word);
48
+ const latin = isCyr ? (0, transliteration_1.cyrillicToLatin)(word) : word;
49
+ const latinLower = latin.toLowerCase();
50
+ const reverseExceptions = {};
51
+ for (const [k, v] of Object.entries(this.exceptions)) {
52
+ reverseExceptions[v] = k;
53
+ }
54
+ let replaced = reverseExceptions[latinLower] ?? null;
55
+ if (replaced === null) {
56
+ const candidates = this._decodeCandidates(latinLower);
57
+ replaced = candidates.length > 0 ? this._pickBestDecodeCandidate(candidates) : latinLower;
58
+ }
59
+ let result = (0, caseHelper_1.applyCase)(latin, replaced);
60
+ if (isCyr) {
61
+ result = (0, transliteration_1.latinToCyrillic)(result, this.softTjToCyrillic, this.plainCTarget);
62
+ }
63
+ return result;
64
+ }
65
+ canDecodeWord(word) {
66
+ if ((0, stringUtils_1.strLen)(word) < this.minWordLength)
67
+ return false;
68
+ const isCyr = (0, transliteration_1.containsCyrillic)(word);
69
+ const latin = isCyr ? (0, transliteration_1.cyrillicToLatin)(word) : word;
70
+ const lower = latin.toLowerCase();
71
+ const reverseExceptions = {};
72
+ for (const [k, v] of Object.entries(this.exceptions)) {
73
+ reverseExceptions[v] = k;
74
+ }
75
+ if (reverseExceptions[lower] !== undefined)
76
+ return true;
77
+ return this._decodeCandidates(lower).length > 0;
78
+ }
79
+ _encodeLatinWord(lowerWord) {
80
+ const exc = this.exceptions[lowerWord];
81
+ if (exc !== undefined)
82
+ return exc;
83
+ return this._encodeLatinWordPlain(lowerWord);
84
+ }
85
+ _encodeLatinWordPlain(lowerWord) {
86
+ const splitIdx = this._findSplitIndex(lowerWord);
87
+ const n = (0, stringUtils_1.strLen)(lowerWord);
88
+ if (splitIdx <= 0 || splitIdx >= n)
89
+ return lowerWord;
90
+ const chars = (0, stringUtils_1.splitChars)(lowerWord);
91
+ return chars.slice(splitIdx).join('') + chars.slice(0, splitIdx).join('');
92
+ }
93
+ _decodeCandidates(lowerWord) {
94
+ const candidates = [];
95
+ const n = (0, stringUtils_1.strLen)(lowerWord);
96
+ const chars = (0, stringUtils_1.splitChars)(lowerWord);
97
+ for (let splitIndex = 1; splitIndex < n; splitIndex++) {
98
+ // Right-rotate by splitIndex: take last splitIndex chars + rest
99
+ const candidate = chars.slice(n - splitIndex).join('') + chars.slice(0, n - splitIndex).join('');
100
+ const encodedWithExc = this._encodeLatinWord(candidate);
101
+ const encodedPlain = this._encodeLatinWordPlain(candidate);
102
+ if (encodedWithExc === lowerWord || encodedPlain === lowerWord) {
103
+ candidates.push([splitIndex, candidate]);
104
+ }
105
+ }
106
+ return candidates;
107
+ }
108
+ _pickBestDecodeCandidate(candidates) {
109
+ const half = (0, stringUtils_1.strLen)(candidates[0][1]) / 2.0;
110
+ const score = ([splitIndex, candidate]) => {
111
+ const secondIsVowel = ((0, stringUtils_1.strLen)(candidate) > 1 && this._isVowelAt(candidate, 1)) ? 1 : 0;
112
+ const startsWithConsonant = (candidate.length > 0 && !this._isVowelAt(candidate, 0)) ? 1 : 0;
113
+ return [Math.abs(splitIndex - half), -secondIsVowel, -startsWithConsonant, splitIndex];
114
+ };
115
+ return candidates.reduce((best, cur) => {
116
+ const bs = score(best);
117
+ const cs = score(cur);
118
+ for (let i = 0; i < 4; i++) {
119
+ if (cs[i] < bs[i])
120
+ return cur;
121
+ if (cs[i] > bs[i])
122
+ return best;
123
+ }
124
+ return best;
125
+ })[1];
126
+ }
127
+ _findSplitIndex(word) {
128
+ const n = (0, stringUtils_1.strLen)(word);
129
+ for (let i = 0; i < n; i++) {
130
+ if (this._isVowelAt(word, i)) {
131
+ let splitIdx = i + 1;
132
+ while (splitIdx < n && this._isVowelAt(word, splitIdx)) {
133
+ splitIdx++;
134
+ }
135
+ return splitIdx;
136
+ }
137
+ }
138
+ return Math.floor(n / 2);
139
+ }
140
+ _isVowelAt(word, i) {
141
+ const chars = (0, stringUtils_1.splitChars)(word);
142
+ if (i < 0 || i >= chars.length)
143
+ return false;
144
+ const ch = chars[i].toLowerCase();
145
+ if (VOWELS.has(ch))
146
+ return true;
147
+ // Syllabic r: 'r' between consonants, not at word edges
148
+ if (ch === 'r' && i > 0 && i < chars.length - 1) {
149
+ const prev = chars[i - 1].toLowerCase();
150
+ const next = chars[i + 1].toLowerCase();
151
+ return !VOWELS.has(prev) && !VOWELS.has(next);
152
+ }
153
+ return false;
154
+ }
155
+ }
156
+ exports.Satrovacki = Satrovacki;
157
+ //# sourceMappingURL=satrovacki.js.map
@@ -0,0 +1,28 @@
1
+ import { SatrovackiOptions } from './satrovacki';
2
+ import { LeetBase } from './leetrovacki';
3
+ import { LeetProfile } from './leet';
4
+ export type Mode = 'auto' | 'satro' | 'utro' | 'leet';
5
+ export type DetectFrom = 'satro' | 'utro' | 'leet' | null;
6
+ export interface SkritOptions {
7
+ mode?: Mode;
8
+ detectFrom?: DetectFrom;
9
+ minWordLength?: number;
10
+ plainCTarget?: string;
11
+ softTjToCyrillic?: boolean;
12
+ exceptions?: Record<string, string>;
13
+ leetBase?: LeetBase;
14
+ leetProfile?: LeetProfile | string;
15
+ leetComplexity?: number;
16
+ leetDensity?: number;
17
+ zaStyle?: '24' | 'z4';
18
+ njeStyle?: 'n73' | 'nj3' | 'њ';
19
+ utroPrefix?: string;
20
+ utroInfix?: string;
21
+ utroSuffix?: string;
22
+ }
23
+ export declare function detectMode(text: string, options?: SkritOptions): 'satro' | 'utro' | 'leet';
24
+ export declare function detectLeetBase(text: string, options?: SkritOptions): 'satro' | 'utro';
25
+ export declare function encodeText(text: string, options?: SkritOptions): string;
26
+ export declare function _deleetTextBasic(text: string): string;
27
+ export declare function _looksLikeSatroEncoded(word: string, options?: SatrovackiOptions): boolean;
28
+ //# sourceMappingURL=skrit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skrit.d.ts","sourceRoot":"","sources":["../src/skrit.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAmC,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAuE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAG1G,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AACtD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,GAAG,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAsB9F;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,GAAG,MAAM,CAWzF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAkD3E;AAsCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcrD;AAiBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAE7F"}