@utilix-tech/sdk 0.30.0 → 0.31.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Full release notes for all Utilix surfaces (browser tools, REST API, SDKs, MCP server) live at [utilix.tech/changelog](https://utilix.tech/changelog). This file tracks just this package.
4
4
 
5
+ ## 0.31.0
6
+ - Add `calculateEmi` (emi-calculator): equated monthly installment, total interest, and a year-by-year principal/interest breakdown from principal, annual rate, and tenure in years or months.
7
+ - Add `parseFrontMatter` (markdown-front-matter-parser): split a Markdown document into its YAML front matter fields and body content, parsing scalars, inline arrays, and block lists.
8
+
5
9
  ## 0.30.0
6
10
  - Add `jsonSchemaToTypescript` (json-schema-to-typescript): convert a JSON Schema document into TypeScript interfaces/types, reading `required`/`enum`/`oneOf`/`anyOf`/`allOf`/`$ref` directly instead of inferring from an example payload.
7
11
  - Add `estimatePasswordEntropy` (password-entropy-estimator): bits of entropy from a password's character pool, a strength label, and crack-time estimates across four guess-rate scenarios.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/sdk
2
2
 
3
- **583 developer utility functions for Node.js: runs locally, no API key required.**
3
+ **585 developer utility functions for Node.js: runs locally, no API key required.**
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@utilix-tech/sdk?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@utilix-tech/sdk)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/@utilix-tech/sdk?style=flat-square)](https://www.npmjs.com/package/@utilix-tech/sdk)
@@ -177,13 +177,13 @@ calculateStringDistance("kitten", "sitting");
177
177
 
178
178
  ---
179
179
 
180
- ### `/data`: CSV / YAML / TOML / XML / INI / NDJSON / .env diff / subtitles
180
+ ### `/data`: CSV / YAML / TOML / XML / INI / NDJSON / .env diff / subtitles / Markdown front matter
181
181
 
182
182
  ```ts
183
183
  import { parseCsv, csvToJson, validateYaml, tomlToJson, jsonToToml,
184
184
  formatXml, xmlToJson, jsonToXml, parseIni,
185
185
  validateNdjson, formatNdjson, ndjsonToJsonArray, diffEnvExample,
186
- parseSubtitles, convertSubtitles, shiftSubtitles } from "@utilix-tech/sdk/data";
186
+ parseSubtitles, convertSubtitles, shiftSubtitles, parseFrontMatter } from "@utilix-tech/sdk/data";
187
187
 
188
188
  // CSV
189
189
  const rows = parseCsv("name,age\nalice,30\nbob,25");
@@ -217,6 +217,10 @@ convertSubtitles("1\n00:00:01,000 --> 00:00:04,000\nHello there.\n", "vtt");
217
217
  // { format: "vtt", sourceFormat: "srt", output: "WEBVTT\n\n00:00:01.000 --> ...", cueCount: 1, ... }
218
218
  shiftSubtitles("1\n00:00:01,000 --> 00:00:04,000\nHi\n", -2.5);
219
219
  // shifts every cue 2.5s earlier, clamping anything below zero to 00:00:00
220
+
221
+ // Markdown front matter: split a document into its YAML front matter and body
222
+ parseFrontMatter("---\ntitle: Hello World\ntags: [foo, bar]\n---\n# Body");
223
+ // { frontMatter: { title: "Hello World", tags: ["foo", "bar"] }, body: "# Body", hasFrontMatter: true, ... }
220
224
  ```
221
225
 
222
226
  ---
@@ -278,7 +282,7 @@ formatIso8601Duration(90061); // { iso: "P1DT1H1M1S", ... }
278
282
  ### `/units`: Conversions
279
283
 
280
284
  ```ts
281
- import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72 } from "@utilix-tech/sdk/units";
285
+ import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72, calculateEmi } from "@utilix-tech/sdk/units";
282
286
 
283
287
  // File sizes
284
288
  convertBytes(1073741824, "GB"); // 1
@@ -368,6 +372,10 @@ calculateVideoBitrate({ mode: "size-from-bitrate", durationSeconds: 600, videoBi
368
372
  // Rule of 72: years to double from a rate, or the rate needed to double in N years
369
373
  calculateRuleOf72(8, "rate-to-years");
370
374
  // { ruleOf72Estimate: 9, exactValue: 9.0065, errorPercent: -0.0718, ... }
375
+
376
+ // EMI: equated monthly installment with a year-by-year principal/interest breakdown
377
+ calculateEmi(500000, 8.5, 5, "years");
378
+ // { emi: 10258.27, totalInterest: 115495.89, tenureMonths: 60, yearlyBreakdown: [...] }
371
379
  ```
372
380
 
373
381
  ---
@@ -647,10 +655,10 @@ readVideoInfo(new Uint8Array(videoBytes));
647
655
  | `@utilix-tech/sdk/encoding` | Base64, URL, HTML entities, Base32/Base58/Base62 encode/decode |
648
656
  | `@utilix-tech/sdk/hashing` | MD5, SHA-1/256/512, bcrypt, HMAC, .htpasswd |
649
657
  | `@utilix-tech/sdk/text` | Case convert, slugify, word count, lorem ipsum, line ops, HTML→Markdown, Levenshtein/Damerau string distance |
650
- | `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, SRT/WebVTT subtitles |
658
+ | `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, SRT/WebVTT subtitles, Markdown front matter parser |
651
659
  | `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, entropy estimator, fake data |
652
660
  | `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
653
- | `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN validation, loan calculator, compound/simple interest calculators, VAT/sales tax calculator, tip/bill split calculator, break-even point calculator, Rule of 72 calculator |
661
+ | `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN validation, loan calculator, EMI calculator, compound/simple interest calculators, VAT/sales tax calculator, tip/bill split calculator, break-even point calculator, Rule of 72 calculator |
654
662
  | `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing, User-Agent parsing, IPv6 address compress/expand |
655
663
  | `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
656
664
  | `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format, MIME type lookup, GitHub URL parsing |
@@ -32,6 +32,7 @@ __export(data_exports, {
32
32
  ndjsonToJsonArray: () => ndjsonToJsonArray,
33
33
  parseCsv: () => parseCsv,
34
34
  parseEnv: () => parseEnv,
35
+ parseFrontMatter: () => parseFrontMatter,
35
36
  parseIni: () => parseIni,
36
37
  parseSubtitleTimestamp: () => parseSubtitleTimestamp,
37
38
  parseSubtitles: () => parseSubtitles,
@@ -1334,5 +1335,69 @@ function shiftSubtitles(input, offsetSeconds, target) {
1334
1335
  warnings
1335
1336
  };
1336
1337
  }
1338
+ function parseFrontMatterScalar(value) {
1339
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1340
+ return value.slice(1, -1);
1341
+ }
1342
+ if (value === "true") return true;
1343
+ if (value === "false") return false;
1344
+ if (value === "null" || value === "~") return null;
1345
+ if (value !== "" && !Number.isNaN(Number(value))) return Number(value);
1346
+ return value;
1347
+ }
1348
+ function parseFrontMatter(input) {
1349
+ if (typeof input !== "string" || input.length === 0) return { error: "input is required" };
1350
+ const normalized = input.replace(/\r\n/g, "\n");
1351
+ if (!normalized.startsWith("---\n") && normalized !== "---") {
1352
+ return { frontMatter: {}, body: input, hasFrontMatter: false, raw: "" };
1353
+ }
1354
+ const closingIdx = normalized.indexOf("\n---", 4);
1355
+ if (closingIdx === -1) {
1356
+ return { error: 'Front matter opening delimiter found but no closing "---" delimiter' };
1357
+ }
1358
+ const raw = normalized.slice(4, closingIdx);
1359
+ let afterClose = normalized.slice(closingIdx + 4);
1360
+ if (afterClose.startsWith("\n")) afterClose = afterClose.slice(1);
1361
+ const frontMatter = {};
1362
+ const rawLines = raw.split("\n");
1363
+ let i = 0;
1364
+ while (i < rawLines.length) {
1365
+ const line = rawLines[i];
1366
+ if (line.trim() === "" || line.trim().startsWith("#")) {
1367
+ i++;
1368
+ continue;
1369
+ }
1370
+ const colonIdx = line.indexOf(":");
1371
+ if (colonIdx === -1) return { error: `Invalid front matter line ${i + 1}: expected "key: value"` };
1372
+ const key = line.slice(0, colonIdx).trim();
1373
+ if (!key) return { error: `Invalid front matter line ${i + 1}: empty key` };
1374
+ const rest = line.slice(colonIdx + 1).trim();
1375
+ if (rest === "") {
1376
+ const listItems = [];
1377
+ let j = i + 1;
1378
+ while (j < rawLines.length && /^\s*-\s+/.test(rawLines[j])) {
1379
+ listItems.push(rawLines[j].replace(/^\s*-\s+/, "").trim());
1380
+ j++;
1381
+ }
1382
+ if (listItems.length > 0) {
1383
+ frontMatter[key] = listItems.map(parseFrontMatterScalar);
1384
+ i = j;
1385
+ continue;
1386
+ }
1387
+ frontMatter[key] = null;
1388
+ i++;
1389
+ continue;
1390
+ }
1391
+ if (rest.startsWith("[") && rest.endsWith("]")) {
1392
+ const inner = rest.slice(1, -1).trim();
1393
+ frontMatter[key] = inner === "" ? [] : inner.split(",").map((s) => parseFrontMatterScalar(s.trim()));
1394
+ i++;
1395
+ continue;
1396
+ }
1397
+ frontMatter[key] = parseFrontMatterScalar(rest);
1398
+ i++;
1399
+ }
1400
+ return { frontMatter, body: afterClose, hasFrontMatter: true, raw };
1401
+ }
1337
1402
 
1338
- export { convertSubtitles, csvToJson, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
1403
+ export { convertSubtitles, csvToJson, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
@@ -22,6 +22,7 @@ __export(units_exports, {
22
22
  calculateBreakEven: () => calculateBreakEven,
23
23
  calculateCompoundInterest: () => calculateCompoundInterest,
24
24
  calculateDiscount: () => calculateDiscount,
25
+ calculateEmi: () => calculateEmi,
25
26
  calculateLoan: () => calculateLoan,
26
27
  calculateMarginMarkup: () => calculateMarginMarkup,
27
28
  calculatePercentageChange: () => calculatePercentageChange,
@@ -1676,5 +1677,60 @@ function calculateRuleOf72(value, direction) {
1676
1677
  errorPercent: round4(errorPercent)
1677
1678
  };
1678
1679
  }
1680
+ function calculateEmi(principal, annualRatePercent, tenure, tenureUnit = "years") {
1681
+ if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a positive number" };
1682
+ if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
1683
+ return { error: "Annual interest rate must be zero or a positive number" };
1684
+ }
1685
+ if (tenureUnit !== "years" && tenureUnit !== "months") {
1686
+ return { error: 'tenureUnit must be "years" or "months"' };
1687
+ }
1688
+ if (!Number.isFinite(tenure) || tenure <= 0) return { error: "Tenure must be a positive number" };
1689
+ const tenureMonths = Math.round(tenureUnit === "years" ? tenure * 12 : tenure);
1690
+ if (tenureMonths <= 0) return { error: "Tenure must resolve to at least 1 month" };
1691
+ const monthlyRate = annualRatePercent / 100 / 12;
1692
+ let emi;
1693
+ if (monthlyRate === 0) {
1694
+ emi = principal / tenureMonths;
1695
+ } else {
1696
+ const factor = Math.pow(1 + monthlyRate, tenureMonths);
1697
+ emi = principal * monthlyRate * factor / (factor - 1);
1698
+ }
1699
+ const yearlyBreakdown = [];
1700
+ let balance = round2(principal);
1701
+ let totalPayment = 0;
1702
+ let yearPrincipal = 0;
1703
+ let yearInterest = 0;
1704
+ let year = 1;
1705
+ for (let month = 1; month <= tenureMonths; month++) {
1706
+ const interest = monthlyRate === 0 ? 0 : round2(balance * monthlyRate);
1707
+ let principalPortion = round2(emi) - interest;
1708
+ if (month === tenureMonths || principalPortion > balance) principalPortion = balance;
1709
+ const payment = round2(principalPortion + interest);
1710
+ balance = Math.max(round2(balance - principalPortion), 0);
1711
+ totalPayment += payment;
1712
+ yearPrincipal += principalPortion;
1713
+ yearInterest += interest;
1714
+ const isYearEnd = month % 12 === 0 || month === tenureMonths;
1715
+ if (isYearEnd) {
1716
+ yearlyBreakdown.push({
1717
+ year,
1718
+ principalPaid: round2(yearPrincipal),
1719
+ interestPaid: round2(yearInterest),
1720
+ balance
1721
+ });
1722
+ year += 1;
1723
+ yearPrincipal = 0;
1724
+ yearInterest = 0;
1725
+ }
1726
+ }
1727
+ return {
1728
+ emi: round2(emi),
1729
+ totalInterest: round2(totalPayment - principal),
1730
+ totalPayment: round2(totalPayment),
1731
+ tenureMonths,
1732
+ yearlyBreakdown
1733
+ };
1734
+ }
1679
1735
 
1680
- export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCompoundInterest, calculateDiscount, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateRuleOf72, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
1736
+ export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCompoundInterest, calculateDiscount, calculateEmi, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateRuleOf72, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
@@ -13,6 +13,7 @@
13
13
  * - env-diff-checker: diffEnvExample
14
14
  * - ndjson-formatter: validateNdjson, minifyNdjson, formatNdjson, ndjsonToJsonArray, jsonArrayToNdjson
15
15
  * - subtitle-converter: parseSubtitleTimestamp, formatSubtitleTimestamp, detectSubtitleFormat, parseSubtitles, serializeSubtitles, convertSubtitles, shiftSubtitles
16
+ * - markdown-front-matter-parser: parseFrontMatter
16
17
  */
17
18
  interface ValidationResult {
18
19
  valid: boolean;
@@ -272,6 +273,24 @@ declare function convertSubtitles(input: string, target: SubtitleFormat, sourceF
272
273
  declare function shiftSubtitles(input: string, offsetSeconds: number, target?: SubtitleFormat): ConvertedSubtitles | {
273
274
  error: string;
274
275
  };
276
+ interface FrontMatterResult {
277
+ frontMatter: Record<string, unknown>;
278
+ body: string;
279
+ hasFrontMatter: boolean;
280
+ raw: string;
281
+ }
282
+ interface FrontMatterError {
283
+ error: string;
284
+ }
285
+ /**
286
+ * Split a Markdown document into its YAML front matter (delimited by --- lines
287
+ * at the top) and body content. Parses simple scalar values (strings, quoted
288
+ * strings, booleans, numbers, null), inline arrays (`tags: [a, b]`), and YAML
289
+ * block lists (`tags:\n - a\n - b`). Not a full YAML parser: nested mappings
290
+ * and multi-line block scalars are not supported. A document with no opening
291
+ * "---" delimiter is returned as-is with `hasFrontMatter: false`.
292
+ */
293
+ declare function parseFrontMatter(input: string): FrontMatterResult | FrontMatterError;
275
294
 
276
295
  type data_ConvertedSubtitles = ConvertedSubtitles;
277
296
  type data_CsvParseResult = CsvParseResult;
@@ -279,6 +298,8 @@ type data_EnvDiffError = EnvDiffError;
279
298
  type data_EnvDiffResult = EnvDiffResult;
280
299
  type data_EnvEntry = EnvEntry;
281
300
  type data_EnvParseResult = EnvParseResult;
301
+ type data_FrontMatterError = FrontMatterError;
302
+ type data_FrontMatterResult = FrontMatterResult;
282
303
  type data_IniSection = IniSection;
283
304
  type data_NdjsonLineResult = NdjsonLineResult;
284
305
  type data_NdjsonValidateResult = NdjsonValidateResult;
@@ -318,6 +339,7 @@ declare const data_minifyXml: typeof minifyXml;
318
339
  declare const data_ndjsonToJsonArray: typeof ndjsonToJsonArray;
319
340
  declare const data_parseCsv: typeof parseCsv;
320
341
  declare const data_parseEnv: typeof parseEnv;
342
+ declare const data_parseFrontMatter: typeof parseFrontMatter;
321
343
  declare const data_parseIni: typeof parseIni;
322
344
  declare const data_parseSubtitleTimestamp: typeof parseSubtitleTimestamp;
323
345
  declare const data_parseSubtitles: typeof parseSubtitles;
@@ -335,7 +357,7 @@ declare const data_validateXml: typeof validateXml;
335
357
  declare const data_validateYaml: typeof validateYaml;
336
358
  declare const data_xmlToJson: typeof xmlToJson;
337
359
  declare namespace data {
338
- export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_IniSection as IniSection, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
360
+ export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
339
361
  }
340
362
 
341
- export { toCsvString as $, iniToJson as A, jsonArrayToNdjson as B, type ConvertedSubtitles as C, jsonToIni as D, type EnvDiffError as E, jsonToToml as F, jsonToXml as G, minifyNdjson as H, type IniSection as I, minifyToml as J, minifyXml as K, ndjsonToJsonArray as L, parseCsv as M, type NdjsonLineResult as N, parseEnv as O, type ParseOptions as P, parseIni as Q, parseSubtitleTimestamp as R, type SubtitleCue as S, type TomlFormatResult as T, parseSubtitles as U, type ValidationResult as V, parseXmlToObject as W, type XmlFormatResult as X, serializeSubtitles as Y, shiftSubtitles as Z, stringifyIni as _, type CsvParseResult as a, tomlToJson as a0, validateEnvKey as a1, validateIni as a2, validateNdjson as a3, validateToml as a4, validateXml as a5, validateYaml as a6, xmlToJson as a7, type EnvDiffResult as b, type EnvEntry as c, data as d, type EnvParseResult as e, type NdjsonValidateResult as f, type ParsedIni as g, type ParsedSubtitles as h, type SubtitleFormat as i, type XmlToJsonOptions as j, convertSubtitles as k, csvToJson as l, detectDelimiter as m, detectSubtitleFormat as n, diffEnvExample as o, envToExport as p, envToJson as q, formatNdjson as r, formatSubtitleTimestamp as s, formatToml as t, formatXml as u, getSection as v, getSectionNames as w, getTomlStats as x, getXmlStats as y, getYamlStats as z };
363
+ export { serializeSubtitles as $, getYamlStats as A, iniToJson as B, type ConvertedSubtitles as C, jsonArrayToNdjson as D, type EnvDiffError as E, type FrontMatterError as F, jsonToIni as G, jsonToToml as H, type IniSection as I, jsonToXml as J, minifyNdjson as K, minifyToml as L, minifyXml as M, type NdjsonLineResult as N, ndjsonToJsonArray as O, type ParseOptions as P, parseCsv as Q, parseEnv as R, type SubtitleCue as S, type TomlFormatResult as T, parseFrontMatter as U, type ValidationResult as V, parseIni as W, type XmlFormatResult as X, parseSubtitleTimestamp as Y, parseSubtitles as Z, parseXmlToObject as _, type CsvParseResult as a, shiftSubtitles as a0, stringifyIni as a1, toCsvString as a2, tomlToJson as a3, validateEnvKey as a4, validateIni as a5, validateNdjson as a6, validateToml as a7, validateXml as a8, validateYaml as a9, xmlToJson as aa, type EnvDiffResult as b, type EnvEntry as c, data as d, type EnvParseResult as e, type FrontMatterResult as f, type NdjsonValidateResult as g, type ParsedIni as h, type ParsedSubtitles as i, type SubtitleFormat as j, type XmlToJsonOptions as k, convertSubtitles as l, csvToJson as m, detectDelimiter as n, detectSubtitleFormat as o, diffEnvExample as p, envToExport as q, envToJson as r, formatNdjson as s, formatSubtitleTimestamp as t, formatToml as u, formatXml as v, getSection as w, getSectionNames as x, getTomlStats as y, getXmlStats as z };
@@ -13,6 +13,7 @@
13
13
  * - env-diff-checker: diffEnvExample
14
14
  * - ndjson-formatter: validateNdjson, minifyNdjson, formatNdjson, ndjsonToJsonArray, jsonArrayToNdjson
15
15
  * - subtitle-converter: parseSubtitleTimestamp, formatSubtitleTimestamp, detectSubtitleFormat, parseSubtitles, serializeSubtitles, convertSubtitles, shiftSubtitles
16
+ * - markdown-front-matter-parser: parseFrontMatter
16
17
  */
17
18
  interface ValidationResult {
18
19
  valid: boolean;
@@ -272,6 +273,24 @@ declare function convertSubtitles(input: string, target: SubtitleFormat, sourceF
272
273
  declare function shiftSubtitles(input: string, offsetSeconds: number, target?: SubtitleFormat): ConvertedSubtitles | {
273
274
  error: string;
274
275
  };
276
+ interface FrontMatterResult {
277
+ frontMatter: Record<string, unknown>;
278
+ body: string;
279
+ hasFrontMatter: boolean;
280
+ raw: string;
281
+ }
282
+ interface FrontMatterError {
283
+ error: string;
284
+ }
285
+ /**
286
+ * Split a Markdown document into its YAML front matter (delimited by --- lines
287
+ * at the top) and body content. Parses simple scalar values (strings, quoted
288
+ * strings, booleans, numbers, null), inline arrays (`tags: [a, b]`), and YAML
289
+ * block lists (`tags:\n - a\n - b`). Not a full YAML parser: nested mappings
290
+ * and multi-line block scalars are not supported. A document with no opening
291
+ * "---" delimiter is returned as-is with `hasFrontMatter: false`.
292
+ */
293
+ declare function parseFrontMatter(input: string): FrontMatterResult | FrontMatterError;
275
294
 
276
295
  type data_ConvertedSubtitles = ConvertedSubtitles;
277
296
  type data_CsvParseResult = CsvParseResult;
@@ -279,6 +298,8 @@ type data_EnvDiffError = EnvDiffError;
279
298
  type data_EnvDiffResult = EnvDiffResult;
280
299
  type data_EnvEntry = EnvEntry;
281
300
  type data_EnvParseResult = EnvParseResult;
301
+ type data_FrontMatterError = FrontMatterError;
302
+ type data_FrontMatterResult = FrontMatterResult;
282
303
  type data_IniSection = IniSection;
283
304
  type data_NdjsonLineResult = NdjsonLineResult;
284
305
  type data_NdjsonValidateResult = NdjsonValidateResult;
@@ -318,6 +339,7 @@ declare const data_minifyXml: typeof minifyXml;
318
339
  declare const data_ndjsonToJsonArray: typeof ndjsonToJsonArray;
319
340
  declare const data_parseCsv: typeof parseCsv;
320
341
  declare const data_parseEnv: typeof parseEnv;
342
+ declare const data_parseFrontMatter: typeof parseFrontMatter;
321
343
  declare const data_parseIni: typeof parseIni;
322
344
  declare const data_parseSubtitleTimestamp: typeof parseSubtitleTimestamp;
323
345
  declare const data_parseSubtitles: typeof parseSubtitles;
@@ -335,7 +357,7 @@ declare const data_validateXml: typeof validateXml;
335
357
  declare const data_validateYaml: typeof validateYaml;
336
358
  declare const data_xmlToJson: typeof xmlToJson;
337
359
  declare namespace data {
338
- export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_IniSection as IniSection, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
360
+ export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
339
361
  }
340
362
 
341
- export { toCsvString as $, iniToJson as A, jsonArrayToNdjson as B, type ConvertedSubtitles as C, jsonToIni as D, type EnvDiffError as E, jsonToToml as F, jsonToXml as G, minifyNdjson as H, type IniSection as I, minifyToml as J, minifyXml as K, ndjsonToJsonArray as L, parseCsv as M, type NdjsonLineResult as N, parseEnv as O, type ParseOptions as P, parseIni as Q, parseSubtitleTimestamp as R, type SubtitleCue as S, type TomlFormatResult as T, parseSubtitles as U, type ValidationResult as V, parseXmlToObject as W, type XmlFormatResult as X, serializeSubtitles as Y, shiftSubtitles as Z, stringifyIni as _, type CsvParseResult as a, tomlToJson as a0, validateEnvKey as a1, validateIni as a2, validateNdjson as a3, validateToml as a4, validateXml as a5, validateYaml as a6, xmlToJson as a7, type EnvDiffResult as b, type EnvEntry as c, data as d, type EnvParseResult as e, type NdjsonValidateResult as f, type ParsedIni as g, type ParsedSubtitles as h, type SubtitleFormat as i, type XmlToJsonOptions as j, convertSubtitles as k, csvToJson as l, detectDelimiter as m, detectSubtitleFormat as n, diffEnvExample as o, envToExport as p, envToJson as q, formatNdjson as r, formatSubtitleTimestamp as s, formatToml as t, formatXml as u, getSection as v, getSectionNames as w, getTomlStats as x, getXmlStats as y, getYamlStats as z };
363
+ export { serializeSubtitles as $, getYamlStats as A, iniToJson as B, type ConvertedSubtitles as C, jsonArrayToNdjson as D, type EnvDiffError as E, type FrontMatterError as F, jsonToIni as G, jsonToToml as H, type IniSection as I, jsonToXml as J, minifyNdjson as K, minifyToml as L, minifyXml as M, type NdjsonLineResult as N, ndjsonToJsonArray as O, type ParseOptions as P, parseCsv as Q, parseEnv as R, type SubtitleCue as S, type TomlFormatResult as T, parseFrontMatter as U, type ValidationResult as V, parseIni as W, type XmlFormatResult as X, parseSubtitleTimestamp as Y, parseSubtitles as Z, parseXmlToObject as _, type CsvParseResult as a, shiftSubtitles as a0, stringifyIni as a1, toCsvString as a2, tomlToJson as a3, validateEnvKey as a4, validateIni as a5, validateNdjson as a6, validateToml as a7, validateXml as a8, validateYaml as a9, xmlToJson as aa, type EnvDiffResult as b, type EnvEntry as c, data as d, type EnvParseResult as e, type FrontMatterResult as f, type NdjsonValidateResult as g, type ParsedIni as h, type ParsedSubtitles as i, type SubtitleFormat as j, type XmlToJsonOptions as k, convertSubtitles as l, csvToJson as m, detectDelimiter as n, detectSubtitleFormat as o, diffEnvExample as p, envToExport as q, envToJson as r, formatNdjson as s, formatSubtitleTimestamp as t, formatToml as u, formatXml as v, getSection as w, getSectionNames as x, getTomlStats as y, getXmlStats as z };
package/dist/index.cjs CHANGED
@@ -4636,6 +4636,7 @@ __export(data_exports, {
4636
4636
  ndjsonToJsonArray: () => ndjsonToJsonArray,
4637
4637
  parseCsv: () => parseCsv,
4638
4638
  parseEnv: () => parseEnv,
4639
+ parseFrontMatter: () => parseFrontMatter,
4639
4640
  parseIni: () => parseIni,
4640
4641
  parseSubtitleTimestamp: () => parseSubtitleTimestamp,
4641
4642
  parseSubtitles: () => parseSubtitles,
@@ -5938,6 +5939,70 @@ function shiftSubtitles(input, offsetSeconds, target) {
5938
5939
  warnings
5939
5940
  };
5940
5941
  }
5942
+ function parseFrontMatterScalar(value) {
5943
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
5944
+ return value.slice(1, -1);
5945
+ }
5946
+ if (value === "true") return true;
5947
+ if (value === "false") return false;
5948
+ if (value === "null" || value === "~") return null;
5949
+ if (value !== "" && !Number.isNaN(Number(value))) return Number(value);
5950
+ return value;
5951
+ }
5952
+ function parseFrontMatter(input) {
5953
+ if (typeof input !== "string" || input.length === 0) return { error: "input is required" };
5954
+ const normalized = input.replace(/\r\n/g, "\n");
5955
+ if (!normalized.startsWith("---\n") && normalized !== "---") {
5956
+ return { frontMatter: {}, body: input, hasFrontMatter: false, raw: "" };
5957
+ }
5958
+ const closingIdx = normalized.indexOf("\n---", 4);
5959
+ if (closingIdx === -1) {
5960
+ return { error: 'Front matter opening delimiter found but no closing "---" delimiter' };
5961
+ }
5962
+ const raw = normalized.slice(4, closingIdx);
5963
+ let afterClose = normalized.slice(closingIdx + 4);
5964
+ if (afterClose.startsWith("\n")) afterClose = afterClose.slice(1);
5965
+ const frontMatter = {};
5966
+ const rawLines = raw.split("\n");
5967
+ let i = 0;
5968
+ while (i < rawLines.length) {
5969
+ const line = rawLines[i];
5970
+ if (line.trim() === "" || line.trim().startsWith("#")) {
5971
+ i++;
5972
+ continue;
5973
+ }
5974
+ const colonIdx = line.indexOf(":");
5975
+ if (colonIdx === -1) return { error: `Invalid front matter line ${i + 1}: expected "key: value"` };
5976
+ const key = line.slice(0, colonIdx).trim();
5977
+ if (!key) return { error: `Invalid front matter line ${i + 1}: empty key` };
5978
+ const rest = line.slice(colonIdx + 1).trim();
5979
+ if (rest === "") {
5980
+ const listItems = [];
5981
+ let j = i + 1;
5982
+ while (j < rawLines.length && /^\s*-\s+/.test(rawLines[j])) {
5983
+ listItems.push(rawLines[j].replace(/^\s*-\s+/, "").trim());
5984
+ j++;
5985
+ }
5986
+ if (listItems.length > 0) {
5987
+ frontMatter[key] = listItems.map(parseFrontMatterScalar);
5988
+ i = j;
5989
+ continue;
5990
+ }
5991
+ frontMatter[key] = null;
5992
+ i++;
5993
+ continue;
5994
+ }
5995
+ if (rest.startsWith("[") && rest.endsWith("]")) {
5996
+ const inner = rest.slice(1, -1).trim();
5997
+ frontMatter[key] = inner === "" ? [] : inner.split(",").map((s) => parseFrontMatterScalar(s.trim()));
5998
+ i++;
5999
+ continue;
6000
+ }
6001
+ frontMatter[key] = parseFrontMatterScalar(rest);
6002
+ i++;
6003
+ }
6004
+ return { frontMatter, body: afterClose, hasFrontMatter: true, raw };
6005
+ }
5941
6006
 
5942
6007
  // src/tools/generators.ts
5943
6008
  var generators_exports = {};
@@ -7357,6 +7422,7 @@ __export(units_exports, {
7357
7422
  calculateBreakEven: () => calculateBreakEven,
7358
7423
  calculateCompoundInterest: () => calculateCompoundInterest,
7359
7424
  calculateDiscount: () => calculateDiscount,
7425
+ calculateEmi: () => calculateEmi,
7360
7426
  calculateLoan: () => calculateLoan,
7361
7427
  calculateMarginMarkup: () => calculateMarginMarkup,
7362
7428
  calculatePercentageChange: () => calculatePercentageChange,
@@ -9011,6 +9077,61 @@ function calculateRuleOf72(value, direction) {
9011
9077
  errorPercent: round4(errorPercent)
9012
9078
  };
9013
9079
  }
9080
+ function calculateEmi(principal, annualRatePercent, tenure, tenureUnit = "years") {
9081
+ if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a positive number" };
9082
+ if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
9083
+ return { error: "Annual interest rate must be zero or a positive number" };
9084
+ }
9085
+ if (tenureUnit !== "years" && tenureUnit !== "months") {
9086
+ return { error: 'tenureUnit must be "years" or "months"' };
9087
+ }
9088
+ if (!Number.isFinite(tenure) || tenure <= 0) return { error: "Tenure must be a positive number" };
9089
+ const tenureMonths = Math.round(tenureUnit === "years" ? tenure * 12 : tenure);
9090
+ if (tenureMonths <= 0) return { error: "Tenure must resolve to at least 1 month" };
9091
+ const monthlyRate = annualRatePercent / 100 / 12;
9092
+ let emi;
9093
+ if (monthlyRate === 0) {
9094
+ emi = principal / tenureMonths;
9095
+ } else {
9096
+ const factor = Math.pow(1 + monthlyRate, tenureMonths);
9097
+ emi = principal * monthlyRate * factor / (factor - 1);
9098
+ }
9099
+ const yearlyBreakdown = [];
9100
+ let balance = round2(principal);
9101
+ let totalPayment = 0;
9102
+ let yearPrincipal = 0;
9103
+ let yearInterest = 0;
9104
+ let year = 1;
9105
+ for (let month = 1; month <= tenureMonths; month++) {
9106
+ const interest = monthlyRate === 0 ? 0 : round2(balance * monthlyRate);
9107
+ let principalPortion = round2(emi) - interest;
9108
+ if (month === tenureMonths || principalPortion > balance) principalPortion = balance;
9109
+ const payment = round2(principalPortion + interest);
9110
+ balance = Math.max(round2(balance - principalPortion), 0);
9111
+ totalPayment += payment;
9112
+ yearPrincipal += principalPortion;
9113
+ yearInterest += interest;
9114
+ const isYearEnd = month % 12 === 0 || month === tenureMonths;
9115
+ if (isYearEnd) {
9116
+ yearlyBreakdown.push({
9117
+ year,
9118
+ principalPaid: round2(yearPrincipal),
9119
+ interestPaid: round2(yearInterest),
9120
+ balance
9121
+ });
9122
+ year += 1;
9123
+ yearPrincipal = 0;
9124
+ yearInterest = 0;
9125
+ }
9126
+ }
9127
+ return {
9128
+ emi: round2(emi),
9129
+ totalInterest: round2(totalPayment - principal),
9130
+ totalPayment: round2(totalPayment),
9131
+ tenureMonths,
9132
+ yearlyBreakdown
9133
+ };
9134
+ }
9014
9135
 
9015
9136
  // src/tools/network.ts
9016
9137
  var network_exports = {};
package/dist/index.d.cts CHANGED
@@ -2,10 +2,10 @@ export { j as json } from './json-Ta9JykSB.cjs';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.cjs';
3
3
  export { h as hashing } from './hashing-CnetQFD_.cjs';
4
4
  export { t as text } from './text-D1fySkCB.cjs';
5
- export { d as data } from './data-XRb0D7Zn.cjs';
5
+ export { d as data } from './data-C4lCByXw.cjs';
6
6
  export { g as generators } from './generators-Du8cBesn.cjs';
7
7
  export { t as time } from './time-KqJjdqII.cjs';
8
- export { u as units } from './units-COt5uI20.cjs';
8
+ export { u as units } from './units-DQYLZd1n.cjs';
9
9
  export { n as network } from './network-D7Epuerc.cjs';
10
10
  export { a as api } from './api-DmTNE4c1.cjs';
11
11
  export { c as code } from './code-DaRvff2v.cjs';
package/dist/index.d.ts CHANGED
@@ -2,10 +2,10 @@ export { j as json } from './json-Ta9JykSB.js';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.js';
3
3
  export { h as hashing } from './hashing-CnetQFD_.js';
4
4
  export { t as text } from './text-D1fySkCB.js';
5
- export { d as data } from './data-XRb0D7Zn.js';
5
+ export { d as data } from './data-C4lCByXw.js';
6
6
  export { g as generators } from './generators-Du8cBesn.js';
7
7
  export { t as time } from './time-KqJjdqII.js';
8
- export { u as units } from './units-COt5uI20.js';
8
+ export { u as units } from './units-DQYLZd1n.js';
9
9
  export { n as network } from './network-D7Epuerc.js';
10
10
  export { a as api } from './api-DmTNE4c1.js';
11
11
  export { c as code } from './code-DaRvff2v.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { media_exports as media } from './chunk-L6V4W4SU.js';
2
- export { units_exports as units } from './chunk-I63BCOAG.js';
2
+ export { units_exports as units } from './chunk-GDIZWDBY.js';
3
3
  export { network_exports as network } from './chunk-CSNTHZHF.js';
4
4
  export { api_exports as api } from './chunk-52ZDKSIX.js';
5
5
  export { code_exports as code } from './chunk-LXKIPPDG.js';
@@ -11,7 +11,7 @@ export { json_exports as json } from './chunk-WVEKRKGU.js';
11
11
  export { encoding_exports as encoding } from './chunk-DOWQZUTP.js';
12
12
  export { hashing_exports as hashing } from './chunk-GEFVMGZR.js';
13
13
  export { text_exports as text } from './chunk-AFEZ6N4A.js';
14
- export { data_exports as data } from './chunk-66QHV5KW.js';
14
+ export { data_exports as data } from './chunk-6FIB72KX.js';
15
15
  export { generators_exports as generators } from './chunk-3TYWIX3B.js';
16
16
  export { time_exports as time } from './chunk-IEPWZERQ.js';
17
17
  import './chunk-MLKGABMK.js';
@@ -1309,6 +1309,70 @@ function shiftSubtitles(input, offsetSeconds, target) {
1309
1309
  warnings
1310
1310
  };
1311
1311
  }
1312
+ function parseFrontMatterScalar(value) {
1313
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1314
+ return value.slice(1, -1);
1315
+ }
1316
+ if (value === "true") return true;
1317
+ if (value === "false") return false;
1318
+ if (value === "null" || value === "~") return null;
1319
+ if (value !== "" && !Number.isNaN(Number(value))) return Number(value);
1320
+ return value;
1321
+ }
1322
+ function parseFrontMatter(input) {
1323
+ if (typeof input !== "string" || input.length === 0) return { error: "input is required" };
1324
+ const normalized = input.replace(/\r\n/g, "\n");
1325
+ if (!normalized.startsWith("---\n") && normalized !== "---") {
1326
+ return { frontMatter: {}, body: input, hasFrontMatter: false, raw: "" };
1327
+ }
1328
+ const closingIdx = normalized.indexOf("\n---", 4);
1329
+ if (closingIdx === -1) {
1330
+ return { error: 'Front matter opening delimiter found but no closing "---" delimiter' };
1331
+ }
1332
+ const raw = normalized.slice(4, closingIdx);
1333
+ let afterClose = normalized.slice(closingIdx + 4);
1334
+ if (afterClose.startsWith("\n")) afterClose = afterClose.slice(1);
1335
+ const frontMatter = {};
1336
+ const rawLines = raw.split("\n");
1337
+ let i = 0;
1338
+ while (i < rawLines.length) {
1339
+ const line = rawLines[i];
1340
+ if (line.trim() === "" || line.trim().startsWith("#")) {
1341
+ i++;
1342
+ continue;
1343
+ }
1344
+ const colonIdx = line.indexOf(":");
1345
+ if (colonIdx === -1) return { error: `Invalid front matter line ${i + 1}: expected "key: value"` };
1346
+ const key = line.slice(0, colonIdx).trim();
1347
+ if (!key) return { error: `Invalid front matter line ${i + 1}: empty key` };
1348
+ const rest = line.slice(colonIdx + 1).trim();
1349
+ if (rest === "") {
1350
+ const listItems = [];
1351
+ let j = i + 1;
1352
+ while (j < rawLines.length && /^\s*-\s+/.test(rawLines[j])) {
1353
+ listItems.push(rawLines[j].replace(/^\s*-\s+/, "").trim());
1354
+ j++;
1355
+ }
1356
+ if (listItems.length > 0) {
1357
+ frontMatter[key] = listItems.map(parseFrontMatterScalar);
1358
+ i = j;
1359
+ continue;
1360
+ }
1361
+ frontMatter[key] = null;
1362
+ i++;
1363
+ continue;
1364
+ }
1365
+ if (rest.startsWith("[") && rest.endsWith("]")) {
1366
+ const inner = rest.slice(1, -1).trim();
1367
+ frontMatter[key] = inner === "" ? [] : inner.split(",").map((s) => parseFrontMatterScalar(s.trim()));
1368
+ i++;
1369
+ continue;
1370
+ }
1371
+ frontMatter[key] = parseFrontMatterScalar(rest);
1372
+ i++;
1373
+ }
1374
+ return { frontMatter, body: afterClose, hasFrontMatter: true, raw };
1375
+ }
1312
1376
 
1313
1377
  exports.convertSubtitles = convertSubtitles;
1314
1378
  exports.csvToJson = csvToJson;
@@ -1337,6 +1401,7 @@ exports.minifyXml = minifyXml;
1337
1401
  exports.ndjsonToJsonArray = ndjsonToJsonArray;
1338
1402
  exports.parseCsv = parseCsv;
1339
1403
  exports.parseEnv = parseEnv;
1404
+ exports.parseFrontMatter = parseFrontMatter;
1340
1405
  exports.parseIni = parseIni;
1341
1406
  exports.parseSubtitleTimestamp = parseSubtitleTimestamp;
1342
1407
  exports.parseSubtitles = parseSubtitles;
@@ -1 +1 @@
1
- export { C as ConvertedSubtitles, a as CsvParseResult, E as EnvDiffError, b as EnvDiffResult, c as EnvEntry, e as EnvParseResult, I as IniSection, N as NdjsonLineResult, f as NdjsonValidateResult, P as ParseOptions, g as ParsedIni, h as ParsedSubtitles, S as SubtitleCue, i as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, j as XmlToJsonOptions, k as convertSubtitles, l as csvToJson, m as detectDelimiter, n as detectSubtitleFormat, o as diffEnvExample, p as envToExport, q as envToJson, r as formatNdjson, s as formatSubtitleTimestamp, t as formatToml, u as formatXml, v as getSection, w as getSectionNames, x as getTomlStats, y as getXmlStats, z as getYamlStats, A as iniToJson, B as jsonArrayToNdjson, D as jsonToIni, F as jsonToToml, G as jsonToXml, H as minifyNdjson, J as minifyToml, K as minifyXml, L as ndjsonToJsonArray, M as parseCsv, O as parseEnv, Q as parseIni, R as parseSubtitleTimestamp, U as parseSubtitles, W as parseXmlToObject, Y as serializeSubtitles, Z as shiftSubtitles, _ as stringifyIni, $ as toCsvString, a0 as tomlToJson, a1 as validateEnvKey, a2 as validateIni, a3 as validateNdjson, a4 as validateToml, a5 as validateXml, a6 as validateYaml, a7 as xmlToJson } from '../data-XRb0D7Zn.cjs';
1
+ export { C as ConvertedSubtitles, a as CsvParseResult, E as EnvDiffError, b as EnvDiffResult, c as EnvEntry, e as EnvParseResult, F as FrontMatterError, f as FrontMatterResult, I as IniSection, N as NdjsonLineResult, g as NdjsonValidateResult, P as ParseOptions, h as ParsedIni, i as ParsedSubtitles, S as SubtitleCue, j as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, k as XmlToJsonOptions, l as convertSubtitles, m as csvToJson, n as detectDelimiter, o as detectSubtitleFormat, p as diffEnvExample, q as envToExport, r as envToJson, s as formatNdjson, t as formatSubtitleTimestamp, u as formatToml, v as formatXml, w as getSection, x as getSectionNames, y as getTomlStats, z as getXmlStats, A as getYamlStats, B as iniToJson, D as jsonArrayToNdjson, G as jsonToIni, H as jsonToToml, J as jsonToXml, K as minifyNdjson, L as minifyToml, M as minifyXml, O as ndjsonToJsonArray, Q as parseCsv, R as parseEnv, U as parseFrontMatter, W as parseIni, Y as parseSubtitleTimestamp, Z as parseSubtitles, _ as parseXmlToObject, $ as serializeSubtitles, a0 as shiftSubtitles, a1 as stringifyIni, a2 as toCsvString, a3 as tomlToJson, a4 as validateEnvKey, a5 as validateIni, a6 as validateNdjson, a7 as validateToml, a8 as validateXml, a9 as validateYaml, aa as xmlToJson } from '../data-C4lCByXw.cjs';
@@ -1 +1 @@
1
- export { C as ConvertedSubtitles, a as CsvParseResult, E as EnvDiffError, b as EnvDiffResult, c as EnvEntry, e as EnvParseResult, I as IniSection, N as NdjsonLineResult, f as NdjsonValidateResult, P as ParseOptions, g as ParsedIni, h as ParsedSubtitles, S as SubtitleCue, i as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, j as XmlToJsonOptions, k as convertSubtitles, l as csvToJson, m as detectDelimiter, n as detectSubtitleFormat, o as diffEnvExample, p as envToExport, q as envToJson, r as formatNdjson, s as formatSubtitleTimestamp, t as formatToml, u as formatXml, v as getSection, w as getSectionNames, x as getTomlStats, y as getXmlStats, z as getYamlStats, A as iniToJson, B as jsonArrayToNdjson, D as jsonToIni, F as jsonToToml, G as jsonToXml, H as minifyNdjson, J as minifyToml, K as minifyXml, L as ndjsonToJsonArray, M as parseCsv, O as parseEnv, Q as parseIni, R as parseSubtitleTimestamp, U as parseSubtitles, W as parseXmlToObject, Y as serializeSubtitles, Z as shiftSubtitles, _ as stringifyIni, $ as toCsvString, a0 as tomlToJson, a1 as validateEnvKey, a2 as validateIni, a3 as validateNdjson, a4 as validateToml, a5 as validateXml, a6 as validateYaml, a7 as xmlToJson } from '../data-XRb0D7Zn.js';
1
+ export { C as ConvertedSubtitles, a as CsvParseResult, E as EnvDiffError, b as EnvDiffResult, c as EnvEntry, e as EnvParseResult, F as FrontMatterError, f as FrontMatterResult, I as IniSection, N as NdjsonLineResult, g as NdjsonValidateResult, P as ParseOptions, h as ParsedIni, i as ParsedSubtitles, S as SubtitleCue, j as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, k as XmlToJsonOptions, l as convertSubtitles, m as csvToJson, n as detectDelimiter, o as detectSubtitleFormat, p as diffEnvExample, q as envToExport, r as envToJson, s as formatNdjson, t as formatSubtitleTimestamp, u as formatToml, v as formatXml, w as getSection, x as getSectionNames, y as getTomlStats, z as getXmlStats, A as getYamlStats, B as iniToJson, D as jsonArrayToNdjson, G as jsonToIni, H as jsonToToml, J as jsonToXml, K as minifyNdjson, L as minifyToml, M as minifyXml, O as ndjsonToJsonArray, Q as parseCsv, R as parseEnv, U as parseFrontMatter, W as parseIni, Y as parseSubtitleTimestamp, Z as parseSubtitles, _ as parseXmlToObject, $ as serializeSubtitles, a0 as shiftSubtitles, a1 as stringifyIni, a2 as toCsvString, a3 as tomlToJson, a4 as validateEnvKey, a5 as validateIni, a6 as validateNdjson, a7 as validateToml, a8 as validateXml, a9 as validateYaml, aa as xmlToJson } from '../data-C4lCByXw.js';
@@ -1,2 +1,2 @@
1
- export { convertSubtitles, csvToJson, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson } from '../chunk-66QHV5KW.js';
1
+ export { convertSubtitles, csvToJson, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson } from '../chunk-6FIB72KX.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -1593,6 +1593,61 @@ function calculateRuleOf72(value, direction) {
1593
1593
  errorPercent: round4(errorPercent)
1594
1594
  };
1595
1595
  }
1596
+ function calculateEmi(principal, annualRatePercent, tenure, tenureUnit = "years") {
1597
+ if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a positive number" };
1598
+ if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
1599
+ return { error: "Annual interest rate must be zero or a positive number" };
1600
+ }
1601
+ if (tenureUnit !== "years" && tenureUnit !== "months") {
1602
+ return { error: 'tenureUnit must be "years" or "months"' };
1603
+ }
1604
+ if (!Number.isFinite(tenure) || tenure <= 0) return { error: "Tenure must be a positive number" };
1605
+ const tenureMonths = Math.round(tenureUnit === "years" ? tenure * 12 : tenure);
1606
+ if (tenureMonths <= 0) return { error: "Tenure must resolve to at least 1 month" };
1607
+ const monthlyRate = annualRatePercent / 100 / 12;
1608
+ let emi;
1609
+ if (monthlyRate === 0) {
1610
+ emi = principal / tenureMonths;
1611
+ } else {
1612
+ const factor = Math.pow(1 + monthlyRate, tenureMonths);
1613
+ emi = principal * monthlyRate * factor / (factor - 1);
1614
+ }
1615
+ const yearlyBreakdown = [];
1616
+ let balance = round2(principal);
1617
+ let totalPayment = 0;
1618
+ let yearPrincipal = 0;
1619
+ let yearInterest = 0;
1620
+ let year = 1;
1621
+ for (let month = 1; month <= tenureMonths; month++) {
1622
+ const interest = monthlyRate === 0 ? 0 : round2(balance * monthlyRate);
1623
+ let principalPortion = round2(emi) - interest;
1624
+ if (month === tenureMonths || principalPortion > balance) principalPortion = balance;
1625
+ const payment = round2(principalPortion + interest);
1626
+ balance = Math.max(round2(balance - principalPortion), 0);
1627
+ totalPayment += payment;
1628
+ yearPrincipal += principalPortion;
1629
+ yearInterest += interest;
1630
+ const isYearEnd = month % 12 === 0 || month === tenureMonths;
1631
+ if (isYearEnd) {
1632
+ yearlyBreakdown.push({
1633
+ year,
1634
+ principalPaid: round2(yearPrincipal),
1635
+ interestPaid: round2(yearInterest),
1636
+ balance
1637
+ });
1638
+ year += 1;
1639
+ yearPrincipal = 0;
1640
+ yearInterest = 0;
1641
+ }
1642
+ }
1643
+ return {
1644
+ emi: round2(emi),
1645
+ totalInterest: round2(totalPayment - principal),
1646
+ totalPayment: round2(totalPayment),
1647
+ tenureMonths,
1648
+ yearlyBreakdown
1649
+ };
1650
+ }
1596
1651
 
1597
1652
  exports.BASE_LABELS = BASE_LABELS;
1598
1653
  exports.BASE_PREFIXES = BASE_PREFIXES;
@@ -1613,6 +1668,7 @@ exports.calcSubnet = calcSubnet;
1613
1668
  exports.calculateBreakEven = calculateBreakEven;
1614
1669
  exports.calculateCompoundInterest = calculateCompoundInterest;
1615
1670
  exports.calculateDiscount = calculateDiscount;
1671
+ exports.calculateEmi = calculateEmi;
1616
1672
  exports.calculateLoan = calculateLoan;
1617
1673
  exports.calculateMarginMarkup = calculateMarginMarkup;
1618
1674
  exports.calculatePercentageChange = calculatePercentageChange;
@@ -1 +1 @@
1
- export { A as AmortizationRow, a as AprApyDirection, b as AprApyResult, c as AspectRatioResult, B as BASE_LABELS, d as BASE_PREFIXES, e as BYTE_UNITS, f as BarcodeFormat, g as BarcodeValidationResult, h as BaseConvertResult, i as BreakEvenInput, j as BreakEvenResult, k as ByteConvertResult, l as ByteUnit, C as COMMON_CURRENCIES, m as COMMON_LOCALES, n as COMMON_PERMISSIONS, o as COMMON_RATIOS, p as COMMON_SIZES, q as COMMON_TAX_RATES, r as COMMON_TIP_PERCENTAGES, s as COMMON_VIEWPORTS, t as CardValidationResult, v as CompoundInterestResult, w as CompoundYearRow, D as Dimensions, x as DiscountField, y as DiscountInput, z as DiscountResult, F as FilePermissions, E as FormatOptions, I as IbanValidationResult, G as IpConversion, H as IsbnFormat, J as IsbnResult, L as LoanResult, M as MarginMarkupField, K as MarginMarkupInput, N as MarginMarkupResult, O as NotationStyle, P as NumberBase, Q as PercentChangeDirection, R as PercentageChangeResult, S as Permission, T as PxConvertResult, U as RuleOf72Direction, V as RuleOf72Result, W as SemverVersion, X as SimpleInterestResult, Y as SubnetInfo, Z as SuccessiveDiscountResult, _ as SuccessiveDiscountStep, $ as TaxDirection, a0 as TaxResult, a1 as TimeValueDirection, a2 as TimeValueResult, a3 as TipSplitResult, a4 as VideoBitrateInput, a5 as VideoBitrateMode, a6 as VideoBitrateResult, a7 as ViewportConvertResult, a8 as applySuccessiveDiscounts, a9 as autoFormat, aa as bumpVersion, ab as calcAspectRatio, ac as calcSubnet, ad as calculateBreakEven, ae as calculateCompoundInterest, af as calculateDiscount, ag as calculateLoan, ah as calculateMarginMarkup, ai as calculatePercentageChange, aj as calculateRuleOf72, ak as calculateSimpleInterest, al as calculateTax, am as calculateTimeValue, an as calculateTipSplit, ao as calculateVideoBitrate, ap as compareSemver, aq as convert, ar as convertAprApy, as as convertBytes, at as convertIp, au as coverBox, av as decimalToIp, aw as decimalToIpCidr, ax as describePermissions, ay as fitIntoBox, az as formatNumber, aA as formatValue, aB as formatVwValue, aC as formatWithSeparator, aD as gcd, aE as ipFromBinary, aF as ipFromDecimal, aG as ipFromHex, aH as ipToBinary, aI as ipToDecimal, aJ as ipToDecimalCidr, aK as ipToHex, aL as ipToOctal, aM as isValid, aN as isValidCidr, aO as isValidIp, aP as isValidIpv4, aQ as marginToMarkup, aR as markupToMargin, aS as octalToPermissions, aT as parseFileSize, aU as parseInput, aV as parseNumberString, aW as parseSemver, aX as permissionsToChmod, aY as permissionsToOctal, aZ as permissionsToSymbolic, a_ as ptToPx, a$ as pxToAll, b0 as pxToViewport, b1 as remToPx, b2 as satisfiesRange, b3 as scaleByHeight, b4 as scaleByWidth, b5 as sortVersions, b6 as splitSubnet, b7 as symbolicToPermissions, b8 as validateBarcode, b9 as validateCardNumber, ba as validateIban, bb as validateIsbn, bc as viewportToPx } from '../units-COt5uI20.cjs';
1
+ export { A as AmortizationRow, a as AprApyDirection, b as AprApyResult, c as AspectRatioResult, B as BASE_LABELS, d as BASE_PREFIXES, e as BYTE_UNITS, f as BarcodeFormat, g as BarcodeValidationResult, h as BaseConvertResult, i as BreakEvenInput, j as BreakEvenResult, k as ByteConvertResult, l as ByteUnit, C as COMMON_CURRENCIES, m as COMMON_LOCALES, n as COMMON_PERMISSIONS, o as COMMON_RATIOS, p as COMMON_SIZES, q as COMMON_TAX_RATES, r as COMMON_TIP_PERCENTAGES, s as COMMON_VIEWPORTS, t as CardValidationResult, v as CompoundInterestResult, w as CompoundYearRow, D as Dimensions, x as DiscountField, y as DiscountInput, z as DiscountResult, E as EmiResult, F as EmiTenureUnit, G as EmiYearlyBreakdownRow, H as FilePermissions, I as FormatOptions, J as IbanValidationResult, K as IpConversion, L as IsbnFormat, M as IsbnResult, N as LoanResult, O as MarginMarkupField, P as MarginMarkupInput, Q as MarginMarkupResult, R as NotationStyle, S as NumberBase, T as PercentChangeDirection, U as PercentageChangeResult, V as Permission, W as PxConvertResult, X as RuleOf72Direction, Y as RuleOf72Result, Z as SemverVersion, _ as SimpleInterestResult, $ as SubnetInfo, a0 as SuccessiveDiscountResult, a1 as SuccessiveDiscountStep, a2 as TaxDirection, a3 as TaxResult, a4 as TimeValueDirection, a5 as TimeValueResult, a6 as TipSplitResult, a7 as VideoBitrateInput, a8 as VideoBitrateMode, a9 as VideoBitrateResult, aa as ViewportConvertResult, ab as applySuccessiveDiscounts, ac as autoFormat, ad as bumpVersion, ae as calcAspectRatio, af as calcSubnet, ag as calculateBreakEven, ah as calculateCompoundInterest, ai as calculateDiscount, aj as calculateEmi, ak as calculateLoan, al as calculateMarginMarkup, am as calculatePercentageChange, an as calculateRuleOf72, ao as calculateSimpleInterest, ap as calculateTax, aq as calculateTimeValue, ar as calculateTipSplit, as as calculateVideoBitrate, at as compareSemver, au as convert, av as convertAprApy, aw as convertBytes, ax as convertIp, ay as coverBox, az as decimalToIp, aA as decimalToIpCidr, aB as describePermissions, aC as fitIntoBox, aD as formatNumber, aE as formatValue, aF as formatVwValue, aG as formatWithSeparator, aH as gcd, aI as ipFromBinary, aJ as ipFromDecimal, aK as ipFromHex, aL as ipToBinary, aM as ipToDecimal, aN as ipToDecimalCidr, aO as ipToHex, aP as ipToOctal, aQ as isValid, aR as isValidCidr, aS as isValidIp, aT as isValidIpv4, aU as marginToMarkup, aV as markupToMargin, aW as octalToPermissions, aX as parseFileSize, aY as parseInput, aZ as parseNumberString, a_ as parseSemver, a$ as permissionsToChmod, b0 as permissionsToOctal, b1 as permissionsToSymbolic, b2 as ptToPx, b3 as pxToAll, b4 as pxToViewport, b5 as remToPx, b6 as satisfiesRange, b7 as scaleByHeight, b8 as scaleByWidth, b9 as sortVersions, ba as splitSubnet, bb as symbolicToPermissions, bc as validateBarcode, bd as validateCardNumber, be as validateIban, bf as validateIsbn, bg as viewportToPx } from '../units-DQYLZd1n.cjs';
@@ -1 +1 @@
1
- export { A as AmortizationRow, a as AprApyDirection, b as AprApyResult, c as AspectRatioResult, B as BASE_LABELS, d as BASE_PREFIXES, e as BYTE_UNITS, f as BarcodeFormat, g as BarcodeValidationResult, h as BaseConvertResult, i as BreakEvenInput, j as BreakEvenResult, k as ByteConvertResult, l as ByteUnit, C as COMMON_CURRENCIES, m as COMMON_LOCALES, n as COMMON_PERMISSIONS, o as COMMON_RATIOS, p as COMMON_SIZES, q as COMMON_TAX_RATES, r as COMMON_TIP_PERCENTAGES, s as COMMON_VIEWPORTS, t as CardValidationResult, v as CompoundInterestResult, w as CompoundYearRow, D as Dimensions, x as DiscountField, y as DiscountInput, z as DiscountResult, F as FilePermissions, E as FormatOptions, I as IbanValidationResult, G as IpConversion, H as IsbnFormat, J as IsbnResult, L as LoanResult, M as MarginMarkupField, K as MarginMarkupInput, N as MarginMarkupResult, O as NotationStyle, P as NumberBase, Q as PercentChangeDirection, R as PercentageChangeResult, S as Permission, T as PxConvertResult, U as RuleOf72Direction, V as RuleOf72Result, W as SemverVersion, X as SimpleInterestResult, Y as SubnetInfo, Z as SuccessiveDiscountResult, _ as SuccessiveDiscountStep, $ as TaxDirection, a0 as TaxResult, a1 as TimeValueDirection, a2 as TimeValueResult, a3 as TipSplitResult, a4 as VideoBitrateInput, a5 as VideoBitrateMode, a6 as VideoBitrateResult, a7 as ViewportConvertResult, a8 as applySuccessiveDiscounts, a9 as autoFormat, aa as bumpVersion, ab as calcAspectRatio, ac as calcSubnet, ad as calculateBreakEven, ae as calculateCompoundInterest, af as calculateDiscount, ag as calculateLoan, ah as calculateMarginMarkup, ai as calculatePercentageChange, aj as calculateRuleOf72, ak as calculateSimpleInterest, al as calculateTax, am as calculateTimeValue, an as calculateTipSplit, ao as calculateVideoBitrate, ap as compareSemver, aq as convert, ar as convertAprApy, as as convertBytes, at as convertIp, au as coverBox, av as decimalToIp, aw as decimalToIpCidr, ax as describePermissions, ay as fitIntoBox, az as formatNumber, aA as formatValue, aB as formatVwValue, aC as formatWithSeparator, aD as gcd, aE as ipFromBinary, aF as ipFromDecimal, aG as ipFromHex, aH as ipToBinary, aI as ipToDecimal, aJ as ipToDecimalCidr, aK as ipToHex, aL as ipToOctal, aM as isValid, aN as isValidCidr, aO as isValidIp, aP as isValidIpv4, aQ as marginToMarkup, aR as markupToMargin, aS as octalToPermissions, aT as parseFileSize, aU as parseInput, aV as parseNumberString, aW as parseSemver, aX as permissionsToChmod, aY as permissionsToOctal, aZ as permissionsToSymbolic, a_ as ptToPx, a$ as pxToAll, b0 as pxToViewport, b1 as remToPx, b2 as satisfiesRange, b3 as scaleByHeight, b4 as scaleByWidth, b5 as sortVersions, b6 as splitSubnet, b7 as symbolicToPermissions, b8 as validateBarcode, b9 as validateCardNumber, ba as validateIban, bb as validateIsbn, bc as viewportToPx } from '../units-COt5uI20.js';
1
+ export { A as AmortizationRow, a as AprApyDirection, b as AprApyResult, c as AspectRatioResult, B as BASE_LABELS, d as BASE_PREFIXES, e as BYTE_UNITS, f as BarcodeFormat, g as BarcodeValidationResult, h as BaseConvertResult, i as BreakEvenInput, j as BreakEvenResult, k as ByteConvertResult, l as ByteUnit, C as COMMON_CURRENCIES, m as COMMON_LOCALES, n as COMMON_PERMISSIONS, o as COMMON_RATIOS, p as COMMON_SIZES, q as COMMON_TAX_RATES, r as COMMON_TIP_PERCENTAGES, s as COMMON_VIEWPORTS, t as CardValidationResult, v as CompoundInterestResult, w as CompoundYearRow, D as Dimensions, x as DiscountField, y as DiscountInput, z as DiscountResult, E as EmiResult, F as EmiTenureUnit, G as EmiYearlyBreakdownRow, H as FilePermissions, I as FormatOptions, J as IbanValidationResult, K as IpConversion, L as IsbnFormat, M as IsbnResult, N as LoanResult, O as MarginMarkupField, P as MarginMarkupInput, Q as MarginMarkupResult, R as NotationStyle, S as NumberBase, T as PercentChangeDirection, U as PercentageChangeResult, V as Permission, W as PxConvertResult, X as RuleOf72Direction, Y as RuleOf72Result, Z as SemverVersion, _ as SimpleInterestResult, $ as SubnetInfo, a0 as SuccessiveDiscountResult, a1 as SuccessiveDiscountStep, a2 as TaxDirection, a3 as TaxResult, a4 as TimeValueDirection, a5 as TimeValueResult, a6 as TipSplitResult, a7 as VideoBitrateInput, a8 as VideoBitrateMode, a9 as VideoBitrateResult, aa as ViewportConvertResult, ab as applySuccessiveDiscounts, ac as autoFormat, ad as bumpVersion, ae as calcAspectRatio, af as calcSubnet, ag as calculateBreakEven, ah as calculateCompoundInterest, ai as calculateDiscount, aj as calculateEmi, ak as calculateLoan, al as calculateMarginMarkup, am as calculatePercentageChange, an as calculateRuleOf72, ao as calculateSimpleInterest, ap as calculateTax, aq as calculateTimeValue, ar as calculateTipSplit, as as calculateVideoBitrate, at as compareSemver, au as convert, av as convertAprApy, aw as convertBytes, ax as convertIp, ay as coverBox, az as decimalToIp, aA as decimalToIpCidr, aB as describePermissions, aC as fitIntoBox, aD as formatNumber, aE as formatValue, aF as formatVwValue, aG as formatWithSeparator, aH as gcd, aI as ipFromBinary, aJ as ipFromDecimal, aK as ipFromHex, aL as ipToBinary, aM as ipToDecimal, aN as ipToDecimalCidr, aO as ipToHex, aP as ipToOctal, aQ as isValid, aR as isValidCidr, aS as isValidIp, aT as isValidIpv4, aU as marginToMarkup, aV as markupToMargin, aW as octalToPermissions, aX as parseFileSize, aY as parseInput, aZ as parseNumberString, a_ as parseSemver, a$ as permissionsToChmod, b0 as permissionsToOctal, b1 as permissionsToSymbolic, b2 as ptToPx, b3 as pxToAll, b4 as pxToViewport, b5 as remToPx, b6 as satisfiesRange, b7 as scaleByHeight, b8 as scaleByWidth, b9 as sortVersions, ba as splitSubnet, bb as symbolicToPermissions, bc as validateBarcode, bd as validateCardNumber, be as validateIban, bf as validateIsbn, bg as viewportToPx } from '../units-DQYLZd1n.js';
@@ -1,2 +1,2 @@
1
- export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCompoundInterest, calculateDiscount, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateRuleOf72, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx } from '../chunk-I63BCOAG.js';
1
+ export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCompoundInterest, calculateDiscount, calculateEmi, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateRuleOf72, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx } from '../chunk-GDIZWDBY.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -28,6 +28,7 @@
28
28
  * - discount-calculator : calculateDiscount, applySuccessiveDiscounts
29
29
  * - break-even-calculator : calculateBreakEven
30
30
  * - video-bitrate-calculator : calculateVideoBitrate
31
+ * - emi-calculator : calculateEmi
31
32
  */
32
33
  interface PxConvertResult {
33
34
  px: number;
@@ -649,6 +650,32 @@ interface RuleOf72Result {
649
650
  declare function calculateRuleOf72(value: number, direction: RuleOf72Direction): RuleOf72Result | {
650
651
  error: string;
651
652
  };
653
+ type EmiTenureUnit = 'years' | 'months';
654
+ interface EmiYearlyBreakdownRow {
655
+ year: number;
656
+ principalPaid: number;
657
+ interestPaid: number;
658
+ balance: number;
659
+ }
660
+ interface EmiResult {
661
+ emi: number;
662
+ totalInterest: number;
663
+ totalPayment: number;
664
+ tenureMonths: number;
665
+ yearlyBreakdown: EmiYearlyBreakdownRow[];
666
+ }
667
+ /**
668
+ * Compute the Equated Monthly Installment (EMI) for a loan given principal,
669
+ * annual interest rate (as a percent, e.g. 8.5), and tenure expressed in
670
+ * either years or months. Uses the standard reducing-balance EMI formula
671
+ * (identical math to a fixed-rate amortizing loan), but reports a
672
+ * year-by-year principal/interest breakdown instead of a full month-by-month
673
+ * schedule, which is the more common way EMI results are presented in
674
+ * lending contexts. Pure arithmetic, no live rate feed.
675
+ */
676
+ declare function calculateEmi(principal: number, annualRatePercent: number, tenure: number, tenureUnit?: EmiTenureUnit): EmiResult | {
677
+ error: string;
678
+ };
652
679
 
653
680
  type units_AmortizationRow = AmortizationRow;
654
681
  type units_AprApyDirection = AprApyDirection;
@@ -679,6 +706,9 @@ type units_Dimensions = Dimensions;
679
706
  type units_DiscountField = DiscountField;
680
707
  type units_DiscountInput = DiscountInput;
681
708
  type units_DiscountResult = DiscountResult;
709
+ type units_EmiResult = EmiResult;
710
+ type units_EmiTenureUnit = EmiTenureUnit;
711
+ type units_EmiYearlyBreakdownRow = EmiYearlyBreakdownRow;
682
712
  type units_FilePermissions = FilePermissions;
683
713
  type units_FormatOptions = FormatOptions;
684
714
  type units_IbanValidationResult = IbanValidationResult;
@@ -719,6 +749,7 @@ declare const units_calcSubnet: typeof calcSubnet;
719
749
  declare const units_calculateBreakEven: typeof calculateBreakEven;
720
750
  declare const units_calculateCompoundInterest: typeof calculateCompoundInterest;
721
751
  declare const units_calculateDiscount: typeof calculateDiscount;
752
+ declare const units_calculateEmi: typeof calculateEmi;
722
753
  declare const units_calculateLoan: typeof calculateLoan;
723
754
  declare const units_calculateMarginMarkup: typeof calculateMarginMarkup;
724
755
  declare const units_calculatePercentageChange: typeof calculatePercentageChange;
@@ -781,7 +812,7 @@ declare const units_validateIban: typeof validateIban;
781
812
  declare const units_validateIsbn: typeof validateIsbn;
782
813
  declare const units_viewportToPx: typeof viewportToPx;
783
814
  declare namespace units {
784
- export { type units_AmortizationRow as AmortizationRow, type units_AprApyDirection as AprApyDirection, type units_AprApyResult as AprApyResult, type units_AspectRatioResult as AspectRatioResult, units_BASE_LABELS as BASE_LABELS, units_BASE_PREFIXES as BASE_PREFIXES, units_BYTE_UNITS as BYTE_UNITS, type units_BarcodeFormat as BarcodeFormat, type units_BarcodeValidationResult as BarcodeValidationResult, type units_BaseConvertResult as BaseConvertResult, type units_BreakEvenInput as BreakEvenInput, type units_BreakEvenResult as BreakEvenResult, type units_ByteConvertResult as ByteConvertResult, type units_ByteUnit as ByteUnit, units_COMMON_CURRENCIES as COMMON_CURRENCIES, units_COMMON_LOCALES as COMMON_LOCALES, units_COMMON_PERMISSIONS as COMMON_PERMISSIONS, units_COMMON_RATIOS as COMMON_RATIOS, units_COMMON_SIZES as COMMON_SIZES, units_COMMON_TAX_RATES as COMMON_TAX_RATES, units_COMMON_TIP_PERCENTAGES as COMMON_TIP_PERCENTAGES, units_COMMON_VIEWPORTS as COMMON_VIEWPORTS, type units_CardValidationResult as CardValidationResult, type units_CompoundInterestResult as CompoundInterestResult, type units_CompoundYearRow as CompoundYearRow, type units_Dimensions as Dimensions, type units_DiscountField as DiscountField, type units_DiscountInput as DiscountInput, type units_DiscountResult as DiscountResult, type units_FilePermissions as FilePermissions, type units_FormatOptions as FormatOptions, type units_IbanValidationResult as IbanValidationResult, type units_IpConversion as IpConversion, type units_IsbnFormat as IsbnFormat, type units_IsbnResult as IsbnResult, type units_LoanResult as LoanResult, type units_MarginMarkupField as MarginMarkupField, type units_MarginMarkupInput as MarginMarkupInput, type units_MarginMarkupResult as MarginMarkupResult, type units_NotationStyle as NotationStyle, type units_NumberBase as NumberBase, type units_PercentChangeDirection as PercentChangeDirection, type units_PercentageChangeResult as PercentageChangeResult, type units_Permission as Permission, type units_PxConvertResult as PxConvertResult, type units_RuleOf72Direction as RuleOf72Direction, type units_RuleOf72Result as RuleOf72Result, type units_SemverVersion as SemverVersion, type units_SimpleInterestResult as SimpleInterestResult, type units_SubnetInfo as SubnetInfo, type units_SuccessiveDiscountResult as SuccessiveDiscountResult, type units_SuccessiveDiscountStep as SuccessiveDiscountStep, type units_TaxDirection as TaxDirection, type units_TaxResult as TaxResult, type units_TimeValueDirection as TimeValueDirection, type units_TimeValueResult as TimeValueResult, type units_TipSplitResult as TipSplitResult, type units_VideoBitrateInput as VideoBitrateInput, type units_VideoBitrateMode as VideoBitrateMode, type units_VideoBitrateResult as VideoBitrateResult, type units_ViewportConvertResult as ViewportConvertResult, units_applySuccessiveDiscounts as applySuccessiveDiscounts, units_autoFormat as autoFormat, units_bumpVersion as bumpVersion, units_calcAspectRatio as calcAspectRatio, units_calcSubnet as calcSubnet, units_calculateBreakEven as calculateBreakEven, units_calculateCompoundInterest as calculateCompoundInterest, units_calculateDiscount as calculateDiscount, units_calculateLoan as calculateLoan, units_calculateMarginMarkup as calculateMarginMarkup, units_calculatePercentageChange as calculatePercentageChange, units_calculateRuleOf72 as calculateRuleOf72, units_calculateSimpleInterest as calculateSimpleInterest, units_calculateTax as calculateTax, units_calculateTimeValue as calculateTimeValue, units_calculateTipSplit as calculateTipSplit, units_calculateVideoBitrate as calculateVideoBitrate, units_compareSemver as compareSemver, units_convert as convert, units_convertAprApy as convertAprApy, units_convertBytes as convertBytes, units_convertIp as convertIp, units_coverBox as coverBox, units_decimalToIp as decimalToIp, units_decimalToIpCidr as decimalToIpCidr, units_describePermissions as describePermissions, units_fitIntoBox as fitIntoBox, units_formatNumber as formatNumber, units_formatValue as formatValue, units_formatVwValue as formatVwValue, units_formatWithSeparator as formatWithSeparator, units_gcd as gcd, units_ipFromBinary as ipFromBinary, units_ipFromDecimal as ipFromDecimal, units_ipFromHex as ipFromHex, units_ipToBinary as ipToBinary, units_ipToDecimal as ipToDecimal, units_ipToDecimalCidr as ipToDecimalCidr, units_ipToHex as ipToHex, units_ipToOctal as ipToOctal, units_isValid as isValid, units_isValidCidr as isValidCidr, units_isValidIp as isValidIp, units_isValidIpv4 as isValidIpv4, units_marginToMarkup as marginToMarkup, units_markupToMargin as markupToMargin, units_octalToPermissions as octalToPermissions, units_parseFileSize as parseFileSize, units_parseInput as parseInput, units_parseNumberString as parseNumberString, units_parseSemver as parseSemver, units_permissionsToChmod as permissionsToChmod, units_permissionsToOctal as permissionsToOctal, units_permissionsToSymbolic as permissionsToSymbolic, units_ptToPx as ptToPx, units_pxToAll as pxToAll, units_pxToViewport as pxToViewport, units_remToPx as remToPx, units_satisfiesRange as satisfiesRange, units_scaleByHeight as scaleByHeight, units_scaleByWidth as scaleByWidth, units_sortVersions as sortVersions, units_splitSubnet as splitSubnet, units_symbolicToPermissions as symbolicToPermissions, units_validateBarcode as validateBarcode, units_validateCardNumber as validateCardNumber, units_validateIban as validateIban, units_validateIsbn as validateIsbn, units_viewportToPx as viewportToPx };
815
+ export { type units_AmortizationRow as AmortizationRow, type units_AprApyDirection as AprApyDirection, type units_AprApyResult as AprApyResult, type units_AspectRatioResult as AspectRatioResult, units_BASE_LABELS as BASE_LABELS, units_BASE_PREFIXES as BASE_PREFIXES, units_BYTE_UNITS as BYTE_UNITS, type units_BarcodeFormat as BarcodeFormat, type units_BarcodeValidationResult as BarcodeValidationResult, type units_BaseConvertResult as BaseConvertResult, type units_BreakEvenInput as BreakEvenInput, type units_BreakEvenResult as BreakEvenResult, type units_ByteConvertResult as ByteConvertResult, type units_ByteUnit as ByteUnit, units_COMMON_CURRENCIES as COMMON_CURRENCIES, units_COMMON_LOCALES as COMMON_LOCALES, units_COMMON_PERMISSIONS as COMMON_PERMISSIONS, units_COMMON_RATIOS as COMMON_RATIOS, units_COMMON_SIZES as COMMON_SIZES, units_COMMON_TAX_RATES as COMMON_TAX_RATES, units_COMMON_TIP_PERCENTAGES as COMMON_TIP_PERCENTAGES, units_COMMON_VIEWPORTS as COMMON_VIEWPORTS, type units_CardValidationResult as CardValidationResult, type units_CompoundInterestResult as CompoundInterestResult, type units_CompoundYearRow as CompoundYearRow, type units_Dimensions as Dimensions, type units_DiscountField as DiscountField, type units_DiscountInput as DiscountInput, type units_DiscountResult as DiscountResult, type units_EmiResult as EmiResult, type units_EmiTenureUnit as EmiTenureUnit, type units_EmiYearlyBreakdownRow as EmiYearlyBreakdownRow, type units_FilePermissions as FilePermissions, type units_FormatOptions as FormatOptions, type units_IbanValidationResult as IbanValidationResult, type units_IpConversion as IpConversion, type units_IsbnFormat as IsbnFormat, type units_IsbnResult as IsbnResult, type units_LoanResult as LoanResult, type units_MarginMarkupField as MarginMarkupField, type units_MarginMarkupInput as MarginMarkupInput, type units_MarginMarkupResult as MarginMarkupResult, type units_NotationStyle as NotationStyle, type units_NumberBase as NumberBase, type units_PercentChangeDirection as PercentChangeDirection, type units_PercentageChangeResult as PercentageChangeResult, type units_Permission as Permission, type units_PxConvertResult as PxConvertResult, type units_RuleOf72Direction as RuleOf72Direction, type units_RuleOf72Result as RuleOf72Result, type units_SemverVersion as SemverVersion, type units_SimpleInterestResult as SimpleInterestResult, type units_SubnetInfo as SubnetInfo, type units_SuccessiveDiscountResult as SuccessiveDiscountResult, type units_SuccessiveDiscountStep as SuccessiveDiscountStep, type units_TaxDirection as TaxDirection, type units_TaxResult as TaxResult, type units_TimeValueDirection as TimeValueDirection, type units_TimeValueResult as TimeValueResult, type units_TipSplitResult as TipSplitResult, type units_VideoBitrateInput as VideoBitrateInput, type units_VideoBitrateMode as VideoBitrateMode, type units_VideoBitrateResult as VideoBitrateResult, type units_ViewportConvertResult as ViewportConvertResult, units_applySuccessiveDiscounts as applySuccessiveDiscounts, units_autoFormat as autoFormat, units_bumpVersion as bumpVersion, units_calcAspectRatio as calcAspectRatio, units_calcSubnet as calcSubnet, units_calculateBreakEven as calculateBreakEven, units_calculateCompoundInterest as calculateCompoundInterest, units_calculateDiscount as calculateDiscount, units_calculateEmi as calculateEmi, units_calculateLoan as calculateLoan, units_calculateMarginMarkup as calculateMarginMarkup, units_calculatePercentageChange as calculatePercentageChange, units_calculateRuleOf72 as calculateRuleOf72, units_calculateSimpleInterest as calculateSimpleInterest, units_calculateTax as calculateTax, units_calculateTimeValue as calculateTimeValue, units_calculateTipSplit as calculateTipSplit, units_calculateVideoBitrate as calculateVideoBitrate, units_compareSemver as compareSemver, units_convert as convert, units_convertAprApy as convertAprApy, units_convertBytes as convertBytes, units_convertIp as convertIp, units_coverBox as coverBox, units_decimalToIp as decimalToIp, units_decimalToIpCidr as decimalToIpCidr, units_describePermissions as describePermissions, units_fitIntoBox as fitIntoBox, units_formatNumber as formatNumber, units_formatValue as formatValue, units_formatVwValue as formatVwValue, units_formatWithSeparator as formatWithSeparator, units_gcd as gcd, units_ipFromBinary as ipFromBinary, units_ipFromDecimal as ipFromDecimal, units_ipFromHex as ipFromHex, units_ipToBinary as ipToBinary, units_ipToDecimal as ipToDecimal, units_ipToDecimalCidr as ipToDecimalCidr, units_ipToHex as ipToHex, units_ipToOctal as ipToOctal, units_isValid as isValid, units_isValidCidr as isValidCidr, units_isValidIp as isValidIp, units_isValidIpv4 as isValidIpv4, units_marginToMarkup as marginToMarkup, units_markupToMargin as markupToMargin, units_octalToPermissions as octalToPermissions, units_parseFileSize as parseFileSize, units_parseInput as parseInput, units_parseNumberString as parseNumberString, units_parseSemver as parseSemver, units_permissionsToChmod as permissionsToChmod, units_permissionsToOctal as permissionsToOctal, units_permissionsToSymbolic as permissionsToSymbolic, units_ptToPx as ptToPx, units_pxToAll as pxToAll, units_pxToViewport as pxToViewport, units_remToPx as remToPx, units_satisfiesRange as satisfiesRange, units_scaleByHeight as scaleByHeight, units_scaleByWidth as scaleByWidth, units_sortVersions as sortVersions, units_splitSubnet as splitSubnet, units_symbolicToPermissions as symbolicToPermissions, units_validateBarcode as validateBarcode, units_validateCardNumber as validateCardNumber, units_validateIban as validateIban, units_validateIsbn as validateIsbn, units_viewportToPx as viewportToPx };
785
816
  }
786
817
 
787
- export { type TaxDirection as $, type AmortizationRow as A, BASE_LABELS as B, COMMON_CURRENCIES as C, type Dimensions as D, type FormatOptions as E, type FilePermissions as F, type IpConversion as G, type IsbnFormat as H, type IbanValidationResult as I, type IsbnResult as J, type MarginMarkupInput as K, type LoanResult as L, type MarginMarkupField as M, type MarginMarkupResult as N, type NotationStyle as O, type NumberBase as P, type PercentChangeDirection as Q, type PercentageChangeResult as R, type Permission as S, type PxConvertResult as T, type RuleOf72Direction as U, type RuleOf72Result as V, type SemverVersion as W, type SimpleInterestResult as X, type SubnetInfo as Y, type SuccessiveDiscountResult as Z, type SuccessiveDiscountStep as _, type AprApyDirection as a, pxToAll as a$, type TaxResult as a0, type TimeValueDirection as a1, type TimeValueResult as a2, type TipSplitResult as a3, type VideoBitrateInput as a4, type VideoBitrateMode as a5, type VideoBitrateResult as a6, type ViewportConvertResult as a7, applySuccessiveDiscounts as a8, autoFormat as a9, formatValue as aA, formatVwValue as aB, formatWithSeparator as aC, gcd as aD, ipFromBinary as aE, ipFromDecimal as aF, ipFromHex as aG, ipToBinary as aH, ipToDecimal as aI, ipToDecimalCidr as aJ, ipToHex as aK, ipToOctal as aL, isValid as aM, isValidCidr as aN, isValidIp as aO, isValidIpv4 as aP, marginToMarkup as aQ, markupToMargin as aR, octalToPermissions as aS, parseFileSize as aT, parseInput as aU, parseNumberString as aV, parseSemver as aW, permissionsToChmod as aX, permissionsToOctal as aY, permissionsToSymbolic as aZ, ptToPx as a_, bumpVersion as aa, calcAspectRatio as ab, calcSubnet as ac, calculateBreakEven as ad, calculateCompoundInterest as ae, calculateDiscount as af, calculateLoan as ag, calculateMarginMarkup as ah, calculatePercentageChange as ai, calculateRuleOf72 as aj, calculateSimpleInterest as ak, calculateTax as al, calculateTimeValue as am, calculateTipSplit as an, calculateVideoBitrate as ao, compareSemver as ap, convert as aq, convertAprApy as ar, convertBytes as as, convertIp as at, coverBox as au, decimalToIp as av, decimalToIpCidr as aw, describePermissions as ax, fitIntoBox as ay, formatNumber as az, type AprApyResult as b, pxToViewport as b0, remToPx as b1, satisfiesRange as b2, scaleByHeight as b3, scaleByWidth as b4, sortVersions as b5, splitSubnet as b6, symbolicToPermissions as b7, validateBarcode as b8, validateCardNumber as b9, validateIban as ba, validateIsbn as bb, viewportToPx as bc, type AspectRatioResult as c, BASE_PREFIXES as d, BYTE_UNITS as e, type BarcodeFormat as f, type BarcodeValidationResult as g, type BaseConvertResult as h, type BreakEvenInput as i, type BreakEvenResult as j, type ByteConvertResult as k, type ByteUnit as l, COMMON_LOCALES as m, COMMON_PERMISSIONS as n, COMMON_RATIOS as o, COMMON_SIZES as p, COMMON_TAX_RATES as q, COMMON_TIP_PERCENTAGES as r, COMMON_VIEWPORTS as s, type CardValidationResult as t, units as u, type CompoundInterestResult as v, type CompoundYearRow as w, type DiscountField as x, type DiscountInput as y, type DiscountResult as z };
818
+ export { type SubnetInfo as $, type AmortizationRow as A, BASE_LABELS as B, COMMON_CURRENCIES as C, type Dimensions as D, type EmiResult as E, type EmiTenureUnit as F, type EmiYearlyBreakdownRow as G, type FilePermissions as H, type FormatOptions as I, type IbanValidationResult as J, type IpConversion as K, type IsbnFormat as L, type IsbnResult as M, type LoanResult as N, type MarginMarkupField as O, type MarginMarkupInput as P, type MarginMarkupResult as Q, type NotationStyle as R, type NumberBase as S, type PercentChangeDirection as T, type PercentageChangeResult as U, type Permission as V, type PxConvertResult as W, type RuleOf72Direction as X, type RuleOf72Result as Y, type SemverVersion as Z, type SimpleInterestResult as _, type AprApyDirection as a, permissionsToChmod as a$, type SuccessiveDiscountResult as a0, type SuccessiveDiscountStep as a1, type TaxDirection as a2, type TaxResult as a3, type TimeValueDirection as a4, type TimeValueResult as a5, type TipSplitResult as a6, type VideoBitrateInput as a7, type VideoBitrateMode as a8, type VideoBitrateResult as a9, decimalToIpCidr as aA, describePermissions as aB, fitIntoBox as aC, formatNumber as aD, formatValue as aE, formatVwValue as aF, formatWithSeparator as aG, gcd as aH, ipFromBinary as aI, ipFromDecimal as aJ, ipFromHex as aK, ipToBinary as aL, ipToDecimal as aM, ipToDecimalCidr as aN, ipToHex as aO, ipToOctal as aP, isValid as aQ, isValidCidr as aR, isValidIp as aS, isValidIpv4 as aT, marginToMarkup as aU, markupToMargin as aV, octalToPermissions as aW, parseFileSize as aX, parseInput as aY, parseNumberString as aZ, parseSemver as a_, type ViewportConvertResult as aa, applySuccessiveDiscounts as ab, autoFormat as ac, bumpVersion as ad, calcAspectRatio as ae, calcSubnet as af, calculateBreakEven as ag, calculateCompoundInterest as ah, calculateDiscount as ai, calculateEmi as aj, calculateLoan as ak, calculateMarginMarkup as al, calculatePercentageChange as am, calculateRuleOf72 as an, calculateSimpleInterest as ao, calculateTax as ap, calculateTimeValue as aq, calculateTipSplit as ar, calculateVideoBitrate as as, compareSemver as at, convert as au, convertAprApy as av, convertBytes as aw, convertIp as ax, coverBox as ay, decimalToIp as az, type AprApyResult as b, permissionsToOctal as b0, permissionsToSymbolic as b1, ptToPx as b2, pxToAll as b3, pxToViewport as b4, remToPx as b5, satisfiesRange as b6, scaleByHeight as b7, scaleByWidth as b8, sortVersions as b9, splitSubnet as ba, symbolicToPermissions as bb, validateBarcode as bc, validateCardNumber as bd, validateIban as be, validateIsbn as bf, viewportToPx as bg, type AspectRatioResult as c, BASE_PREFIXES as d, BYTE_UNITS as e, type BarcodeFormat as f, type BarcodeValidationResult as g, type BaseConvertResult as h, type BreakEvenInput as i, type BreakEvenResult as j, type ByteConvertResult as k, type ByteUnit as l, COMMON_LOCALES as m, COMMON_PERMISSIONS as n, COMMON_RATIOS as o, COMMON_SIZES as p, COMMON_TAX_RATES as q, COMMON_TIP_PERCENTAGES as r, COMMON_VIEWPORTS as s, type CardValidationResult as t, units as u, type CompoundInterestResult as v, type CompoundYearRow as w, type DiscountField as x, type DiscountInput as y, type DiscountResult as z };
@@ -28,6 +28,7 @@
28
28
  * - discount-calculator : calculateDiscount, applySuccessiveDiscounts
29
29
  * - break-even-calculator : calculateBreakEven
30
30
  * - video-bitrate-calculator : calculateVideoBitrate
31
+ * - emi-calculator : calculateEmi
31
32
  */
32
33
  interface PxConvertResult {
33
34
  px: number;
@@ -649,6 +650,32 @@ interface RuleOf72Result {
649
650
  declare function calculateRuleOf72(value: number, direction: RuleOf72Direction): RuleOf72Result | {
650
651
  error: string;
651
652
  };
653
+ type EmiTenureUnit = 'years' | 'months';
654
+ interface EmiYearlyBreakdownRow {
655
+ year: number;
656
+ principalPaid: number;
657
+ interestPaid: number;
658
+ balance: number;
659
+ }
660
+ interface EmiResult {
661
+ emi: number;
662
+ totalInterest: number;
663
+ totalPayment: number;
664
+ tenureMonths: number;
665
+ yearlyBreakdown: EmiYearlyBreakdownRow[];
666
+ }
667
+ /**
668
+ * Compute the Equated Monthly Installment (EMI) for a loan given principal,
669
+ * annual interest rate (as a percent, e.g. 8.5), and tenure expressed in
670
+ * either years or months. Uses the standard reducing-balance EMI formula
671
+ * (identical math to a fixed-rate amortizing loan), but reports a
672
+ * year-by-year principal/interest breakdown instead of a full month-by-month
673
+ * schedule, which is the more common way EMI results are presented in
674
+ * lending contexts. Pure arithmetic, no live rate feed.
675
+ */
676
+ declare function calculateEmi(principal: number, annualRatePercent: number, tenure: number, tenureUnit?: EmiTenureUnit): EmiResult | {
677
+ error: string;
678
+ };
652
679
 
653
680
  type units_AmortizationRow = AmortizationRow;
654
681
  type units_AprApyDirection = AprApyDirection;
@@ -679,6 +706,9 @@ type units_Dimensions = Dimensions;
679
706
  type units_DiscountField = DiscountField;
680
707
  type units_DiscountInput = DiscountInput;
681
708
  type units_DiscountResult = DiscountResult;
709
+ type units_EmiResult = EmiResult;
710
+ type units_EmiTenureUnit = EmiTenureUnit;
711
+ type units_EmiYearlyBreakdownRow = EmiYearlyBreakdownRow;
682
712
  type units_FilePermissions = FilePermissions;
683
713
  type units_FormatOptions = FormatOptions;
684
714
  type units_IbanValidationResult = IbanValidationResult;
@@ -719,6 +749,7 @@ declare const units_calcSubnet: typeof calcSubnet;
719
749
  declare const units_calculateBreakEven: typeof calculateBreakEven;
720
750
  declare const units_calculateCompoundInterest: typeof calculateCompoundInterest;
721
751
  declare const units_calculateDiscount: typeof calculateDiscount;
752
+ declare const units_calculateEmi: typeof calculateEmi;
722
753
  declare const units_calculateLoan: typeof calculateLoan;
723
754
  declare const units_calculateMarginMarkup: typeof calculateMarginMarkup;
724
755
  declare const units_calculatePercentageChange: typeof calculatePercentageChange;
@@ -781,7 +812,7 @@ declare const units_validateIban: typeof validateIban;
781
812
  declare const units_validateIsbn: typeof validateIsbn;
782
813
  declare const units_viewportToPx: typeof viewportToPx;
783
814
  declare namespace units {
784
- export { type units_AmortizationRow as AmortizationRow, type units_AprApyDirection as AprApyDirection, type units_AprApyResult as AprApyResult, type units_AspectRatioResult as AspectRatioResult, units_BASE_LABELS as BASE_LABELS, units_BASE_PREFIXES as BASE_PREFIXES, units_BYTE_UNITS as BYTE_UNITS, type units_BarcodeFormat as BarcodeFormat, type units_BarcodeValidationResult as BarcodeValidationResult, type units_BaseConvertResult as BaseConvertResult, type units_BreakEvenInput as BreakEvenInput, type units_BreakEvenResult as BreakEvenResult, type units_ByteConvertResult as ByteConvertResult, type units_ByteUnit as ByteUnit, units_COMMON_CURRENCIES as COMMON_CURRENCIES, units_COMMON_LOCALES as COMMON_LOCALES, units_COMMON_PERMISSIONS as COMMON_PERMISSIONS, units_COMMON_RATIOS as COMMON_RATIOS, units_COMMON_SIZES as COMMON_SIZES, units_COMMON_TAX_RATES as COMMON_TAX_RATES, units_COMMON_TIP_PERCENTAGES as COMMON_TIP_PERCENTAGES, units_COMMON_VIEWPORTS as COMMON_VIEWPORTS, type units_CardValidationResult as CardValidationResult, type units_CompoundInterestResult as CompoundInterestResult, type units_CompoundYearRow as CompoundYearRow, type units_Dimensions as Dimensions, type units_DiscountField as DiscountField, type units_DiscountInput as DiscountInput, type units_DiscountResult as DiscountResult, type units_FilePermissions as FilePermissions, type units_FormatOptions as FormatOptions, type units_IbanValidationResult as IbanValidationResult, type units_IpConversion as IpConversion, type units_IsbnFormat as IsbnFormat, type units_IsbnResult as IsbnResult, type units_LoanResult as LoanResult, type units_MarginMarkupField as MarginMarkupField, type units_MarginMarkupInput as MarginMarkupInput, type units_MarginMarkupResult as MarginMarkupResult, type units_NotationStyle as NotationStyle, type units_NumberBase as NumberBase, type units_PercentChangeDirection as PercentChangeDirection, type units_PercentageChangeResult as PercentageChangeResult, type units_Permission as Permission, type units_PxConvertResult as PxConvertResult, type units_RuleOf72Direction as RuleOf72Direction, type units_RuleOf72Result as RuleOf72Result, type units_SemverVersion as SemverVersion, type units_SimpleInterestResult as SimpleInterestResult, type units_SubnetInfo as SubnetInfo, type units_SuccessiveDiscountResult as SuccessiveDiscountResult, type units_SuccessiveDiscountStep as SuccessiveDiscountStep, type units_TaxDirection as TaxDirection, type units_TaxResult as TaxResult, type units_TimeValueDirection as TimeValueDirection, type units_TimeValueResult as TimeValueResult, type units_TipSplitResult as TipSplitResult, type units_VideoBitrateInput as VideoBitrateInput, type units_VideoBitrateMode as VideoBitrateMode, type units_VideoBitrateResult as VideoBitrateResult, type units_ViewportConvertResult as ViewportConvertResult, units_applySuccessiveDiscounts as applySuccessiveDiscounts, units_autoFormat as autoFormat, units_bumpVersion as bumpVersion, units_calcAspectRatio as calcAspectRatio, units_calcSubnet as calcSubnet, units_calculateBreakEven as calculateBreakEven, units_calculateCompoundInterest as calculateCompoundInterest, units_calculateDiscount as calculateDiscount, units_calculateLoan as calculateLoan, units_calculateMarginMarkup as calculateMarginMarkup, units_calculatePercentageChange as calculatePercentageChange, units_calculateRuleOf72 as calculateRuleOf72, units_calculateSimpleInterest as calculateSimpleInterest, units_calculateTax as calculateTax, units_calculateTimeValue as calculateTimeValue, units_calculateTipSplit as calculateTipSplit, units_calculateVideoBitrate as calculateVideoBitrate, units_compareSemver as compareSemver, units_convert as convert, units_convertAprApy as convertAprApy, units_convertBytes as convertBytes, units_convertIp as convertIp, units_coverBox as coverBox, units_decimalToIp as decimalToIp, units_decimalToIpCidr as decimalToIpCidr, units_describePermissions as describePermissions, units_fitIntoBox as fitIntoBox, units_formatNumber as formatNumber, units_formatValue as formatValue, units_formatVwValue as formatVwValue, units_formatWithSeparator as formatWithSeparator, units_gcd as gcd, units_ipFromBinary as ipFromBinary, units_ipFromDecimal as ipFromDecimal, units_ipFromHex as ipFromHex, units_ipToBinary as ipToBinary, units_ipToDecimal as ipToDecimal, units_ipToDecimalCidr as ipToDecimalCidr, units_ipToHex as ipToHex, units_ipToOctal as ipToOctal, units_isValid as isValid, units_isValidCidr as isValidCidr, units_isValidIp as isValidIp, units_isValidIpv4 as isValidIpv4, units_marginToMarkup as marginToMarkup, units_markupToMargin as markupToMargin, units_octalToPermissions as octalToPermissions, units_parseFileSize as parseFileSize, units_parseInput as parseInput, units_parseNumberString as parseNumberString, units_parseSemver as parseSemver, units_permissionsToChmod as permissionsToChmod, units_permissionsToOctal as permissionsToOctal, units_permissionsToSymbolic as permissionsToSymbolic, units_ptToPx as ptToPx, units_pxToAll as pxToAll, units_pxToViewport as pxToViewport, units_remToPx as remToPx, units_satisfiesRange as satisfiesRange, units_scaleByHeight as scaleByHeight, units_scaleByWidth as scaleByWidth, units_sortVersions as sortVersions, units_splitSubnet as splitSubnet, units_symbolicToPermissions as symbolicToPermissions, units_validateBarcode as validateBarcode, units_validateCardNumber as validateCardNumber, units_validateIban as validateIban, units_validateIsbn as validateIsbn, units_viewportToPx as viewportToPx };
815
+ export { type units_AmortizationRow as AmortizationRow, type units_AprApyDirection as AprApyDirection, type units_AprApyResult as AprApyResult, type units_AspectRatioResult as AspectRatioResult, units_BASE_LABELS as BASE_LABELS, units_BASE_PREFIXES as BASE_PREFIXES, units_BYTE_UNITS as BYTE_UNITS, type units_BarcodeFormat as BarcodeFormat, type units_BarcodeValidationResult as BarcodeValidationResult, type units_BaseConvertResult as BaseConvertResult, type units_BreakEvenInput as BreakEvenInput, type units_BreakEvenResult as BreakEvenResult, type units_ByteConvertResult as ByteConvertResult, type units_ByteUnit as ByteUnit, units_COMMON_CURRENCIES as COMMON_CURRENCIES, units_COMMON_LOCALES as COMMON_LOCALES, units_COMMON_PERMISSIONS as COMMON_PERMISSIONS, units_COMMON_RATIOS as COMMON_RATIOS, units_COMMON_SIZES as COMMON_SIZES, units_COMMON_TAX_RATES as COMMON_TAX_RATES, units_COMMON_TIP_PERCENTAGES as COMMON_TIP_PERCENTAGES, units_COMMON_VIEWPORTS as COMMON_VIEWPORTS, type units_CardValidationResult as CardValidationResult, type units_CompoundInterestResult as CompoundInterestResult, type units_CompoundYearRow as CompoundYearRow, type units_Dimensions as Dimensions, type units_DiscountField as DiscountField, type units_DiscountInput as DiscountInput, type units_DiscountResult as DiscountResult, type units_EmiResult as EmiResult, type units_EmiTenureUnit as EmiTenureUnit, type units_EmiYearlyBreakdownRow as EmiYearlyBreakdownRow, type units_FilePermissions as FilePermissions, type units_FormatOptions as FormatOptions, type units_IbanValidationResult as IbanValidationResult, type units_IpConversion as IpConversion, type units_IsbnFormat as IsbnFormat, type units_IsbnResult as IsbnResult, type units_LoanResult as LoanResult, type units_MarginMarkupField as MarginMarkupField, type units_MarginMarkupInput as MarginMarkupInput, type units_MarginMarkupResult as MarginMarkupResult, type units_NotationStyle as NotationStyle, type units_NumberBase as NumberBase, type units_PercentChangeDirection as PercentChangeDirection, type units_PercentageChangeResult as PercentageChangeResult, type units_Permission as Permission, type units_PxConvertResult as PxConvertResult, type units_RuleOf72Direction as RuleOf72Direction, type units_RuleOf72Result as RuleOf72Result, type units_SemverVersion as SemverVersion, type units_SimpleInterestResult as SimpleInterestResult, type units_SubnetInfo as SubnetInfo, type units_SuccessiveDiscountResult as SuccessiveDiscountResult, type units_SuccessiveDiscountStep as SuccessiveDiscountStep, type units_TaxDirection as TaxDirection, type units_TaxResult as TaxResult, type units_TimeValueDirection as TimeValueDirection, type units_TimeValueResult as TimeValueResult, type units_TipSplitResult as TipSplitResult, type units_VideoBitrateInput as VideoBitrateInput, type units_VideoBitrateMode as VideoBitrateMode, type units_VideoBitrateResult as VideoBitrateResult, type units_ViewportConvertResult as ViewportConvertResult, units_applySuccessiveDiscounts as applySuccessiveDiscounts, units_autoFormat as autoFormat, units_bumpVersion as bumpVersion, units_calcAspectRatio as calcAspectRatio, units_calcSubnet as calcSubnet, units_calculateBreakEven as calculateBreakEven, units_calculateCompoundInterest as calculateCompoundInterest, units_calculateDiscount as calculateDiscount, units_calculateEmi as calculateEmi, units_calculateLoan as calculateLoan, units_calculateMarginMarkup as calculateMarginMarkup, units_calculatePercentageChange as calculatePercentageChange, units_calculateRuleOf72 as calculateRuleOf72, units_calculateSimpleInterest as calculateSimpleInterest, units_calculateTax as calculateTax, units_calculateTimeValue as calculateTimeValue, units_calculateTipSplit as calculateTipSplit, units_calculateVideoBitrate as calculateVideoBitrate, units_compareSemver as compareSemver, units_convert as convert, units_convertAprApy as convertAprApy, units_convertBytes as convertBytes, units_convertIp as convertIp, units_coverBox as coverBox, units_decimalToIp as decimalToIp, units_decimalToIpCidr as decimalToIpCidr, units_describePermissions as describePermissions, units_fitIntoBox as fitIntoBox, units_formatNumber as formatNumber, units_formatValue as formatValue, units_formatVwValue as formatVwValue, units_formatWithSeparator as formatWithSeparator, units_gcd as gcd, units_ipFromBinary as ipFromBinary, units_ipFromDecimal as ipFromDecimal, units_ipFromHex as ipFromHex, units_ipToBinary as ipToBinary, units_ipToDecimal as ipToDecimal, units_ipToDecimalCidr as ipToDecimalCidr, units_ipToHex as ipToHex, units_ipToOctal as ipToOctal, units_isValid as isValid, units_isValidCidr as isValidCidr, units_isValidIp as isValidIp, units_isValidIpv4 as isValidIpv4, units_marginToMarkup as marginToMarkup, units_markupToMargin as markupToMargin, units_octalToPermissions as octalToPermissions, units_parseFileSize as parseFileSize, units_parseInput as parseInput, units_parseNumberString as parseNumberString, units_parseSemver as parseSemver, units_permissionsToChmod as permissionsToChmod, units_permissionsToOctal as permissionsToOctal, units_permissionsToSymbolic as permissionsToSymbolic, units_ptToPx as ptToPx, units_pxToAll as pxToAll, units_pxToViewport as pxToViewport, units_remToPx as remToPx, units_satisfiesRange as satisfiesRange, units_scaleByHeight as scaleByHeight, units_scaleByWidth as scaleByWidth, units_sortVersions as sortVersions, units_splitSubnet as splitSubnet, units_symbolicToPermissions as symbolicToPermissions, units_validateBarcode as validateBarcode, units_validateCardNumber as validateCardNumber, units_validateIban as validateIban, units_validateIsbn as validateIsbn, units_viewportToPx as viewportToPx };
785
816
  }
786
817
 
787
- export { type TaxDirection as $, type AmortizationRow as A, BASE_LABELS as B, COMMON_CURRENCIES as C, type Dimensions as D, type FormatOptions as E, type FilePermissions as F, type IpConversion as G, type IsbnFormat as H, type IbanValidationResult as I, type IsbnResult as J, type MarginMarkupInput as K, type LoanResult as L, type MarginMarkupField as M, type MarginMarkupResult as N, type NotationStyle as O, type NumberBase as P, type PercentChangeDirection as Q, type PercentageChangeResult as R, type Permission as S, type PxConvertResult as T, type RuleOf72Direction as U, type RuleOf72Result as V, type SemverVersion as W, type SimpleInterestResult as X, type SubnetInfo as Y, type SuccessiveDiscountResult as Z, type SuccessiveDiscountStep as _, type AprApyDirection as a, pxToAll as a$, type TaxResult as a0, type TimeValueDirection as a1, type TimeValueResult as a2, type TipSplitResult as a3, type VideoBitrateInput as a4, type VideoBitrateMode as a5, type VideoBitrateResult as a6, type ViewportConvertResult as a7, applySuccessiveDiscounts as a8, autoFormat as a9, formatValue as aA, formatVwValue as aB, formatWithSeparator as aC, gcd as aD, ipFromBinary as aE, ipFromDecimal as aF, ipFromHex as aG, ipToBinary as aH, ipToDecimal as aI, ipToDecimalCidr as aJ, ipToHex as aK, ipToOctal as aL, isValid as aM, isValidCidr as aN, isValidIp as aO, isValidIpv4 as aP, marginToMarkup as aQ, markupToMargin as aR, octalToPermissions as aS, parseFileSize as aT, parseInput as aU, parseNumberString as aV, parseSemver as aW, permissionsToChmod as aX, permissionsToOctal as aY, permissionsToSymbolic as aZ, ptToPx as a_, bumpVersion as aa, calcAspectRatio as ab, calcSubnet as ac, calculateBreakEven as ad, calculateCompoundInterest as ae, calculateDiscount as af, calculateLoan as ag, calculateMarginMarkup as ah, calculatePercentageChange as ai, calculateRuleOf72 as aj, calculateSimpleInterest as ak, calculateTax as al, calculateTimeValue as am, calculateTipSplit as an, calculateVideoBitrate as ao, compareSemver as ap, convert as aq, convertAprApy as ar, convertBytes as as, convertIp as at, coverBox as au, decimalToIp as av, decimalToIpCidr as aw, describePermissions as ax, fitIntoBox as ay, formatNumber as az, type AprApyResult as b, pxToViewport as b0, remToPx as b1, satisfiesRange as b2, scaleByHeight as b3, scaleByWidth as b4, sortVersions as b5, splitSubnet as b6, symbolicToPermissions as b7, validateBarcode as b8, validateCardNumber as b9, validateIban as ba, validateIsbn as bb, viewportToPx as bc, type AspectRatioResult as c, BASE_PREFIXES as d, BYTE_UNITS as e, type BarcodeFormat as f, type BarcodeValidationResult as g, type BaseConvertResult as h, type BreakEvenInput as i, type BreakEvenResult as j, type ByteConvertResult as k, type ByteUnit as l, COMMON_LOCALES as m, COMMON_PERMISSIONS as n, COMMON_RATIOS as o, COMMON_SIZES as p, COMMON_TAX_RATES as q, COMMON_TIP_PERCENTAGES as r, COMMON_VIEWPORTS as s, type CardValidationResult as t, units as u, type CompoundInterestResult as v, type CompoundYearRow as w, type DiscountField as x, type DiscountInput as y, type DiscountResult as z };
818
+ export { type SubnetInfo as $, type AmortizationRow as A, BASE_LABELS as B, COMMON_CURRENCIES as C, type Dimensions as D, type EmiResult as E, type EmiTenureUnit as F, type EmiYearlyBreakdownRow as G, type FilePermissions as H, type FormatOptions as I, type IbanValidationResult as J, type IpConversion as K, type IsbnFormat as L, type IsbnResult as M, type LoanResult as N, type MarginMarkupField as O, type MarginMarkupInput as P, type MarginMarkupResult as Q, type NotationStyle as R, type NumberBase as S, type PercentChangeDirection as T, type PercentageChangeResult as U, type Permission as V, type PxConvertResult as W, type RuleOf72Direction as X, type RuleOf72Result as Y, type SemverVersion as Z, type SimpleInterestResult as _, type AprApyDirection as a, permissionsToChmod as a$, type SuccessiveDiscountResult as a0, type SuccessiveDiscountStep as a1, type TaxDirection as a2, type TaxResult as a3, type TimeValueDirection as a4, type TimeValueResult as a5, type TipSplitResult as a6, type VideoBitrateInput as a7, type VideoBitrateMode as a8, type VideoBitrateResult as a9, decimalToIpCidr as aA, describePermissions as aB, fitIntoBox as aC, formatNumber as aD, formatValue as aE, formatVwValue as aF, formatWithSeparator as aG, gcd as aH, ipFromBinary as aI, ipFromDecimal as aJ, ipFromHex as aK, ipToBinary as aL, ipToDecimal as aM, ipToDecimalCidr as aN, ipToHex as aO, ipToOctal as aP, isValid as aQ, isValidCidr as aR, isValidIp as aS, isValidIpv4 as aT, marginToMarkup as aU, markupToMargin as aV, octalToPermissions as aW, parseFileSize as aX, parseInput as aY, parseNumberString as aZ, parseSemver as a_, type ViewportConvertResult as aa, applySuccessiveDiscounts as ab, autoFormat as ac, bumpVersion as ad, calcAspectRatio as ae, calcSubnet as af, calculateBreakEven as ag, calculateCompoundInterest as ah, calculateDiscount as ai, calculateEmi as aj, calculateLoan as ak, calculateMarginMarkup as al, calculatePercentageChange as am, calculateRuleOf72 as an, calculateSimpleInterest as ao, calculateTax as ap, calculateTimeValue as aq, calculateTipSplit as ar, calculateVideoBitrate as as, compareSemver as at, convert as au, convertAprApy as av, convertBytes as aw, convertIp as ax, coverBox as ay, decimalToIp as az, type AprApyResult as b, permissionsToOctal as b0, permissionsToSymbolic as b1, ptToPx as b2, pxToAll as b3, pxToViewport as b4, remToPx as b5, satisfiesRange as b6, scaleByHeight as b7, scaleByWidth as b8, sortVersions as b9, splitSubnet as ba, symbolicToPermissions as bb, validateBarcode as bc, validateCardNumber as bd, validateIban as be, validateIsbn as bf, viewportToPx as bg, type AspectRatioResult as c, BASE_PREFIXES as d, BYTE_UNITS as e, type BarcodeFormat as f, type BarcodeValidationResult as g, type BaseConvertResult as h, type BreakEvenInput as i, type BreakEvenResult as j, type ByteConvertResult as k, type ByteUnit as l, COMMON_LOCALES as m, COMMON_PERMISSIONS as n, COMMON_RATIOS as o, COMMON_SIZES as p, COMMON_TAX_RATES as q, COMMON_TIP_PERCENTAGES as r, COMMON_VIEWPORTS as s, type CardValidationResult as t, units as u, type CompoundInterestResult as v, type CompoundYearRow as w, type DiscountField as x, type DiscountInput as y, type DiscountResult as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilix-tech/sdk",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "154+ developer utility tools for Node.js: JSON, encoding, hashing, color, CSS, network and more. Runs locally, no API key required.",
5
5
  "author": "Utilix <hello@utilix.tech>",
6
6
  "license": "MIT",