@utilix-tech/sdk 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +15 -6
  3. package/dist/{chunk-CSNTHZHF.js → chunk-3YUKLV5N.js} +81 -1
  4. package/dist/{chunk-LXKIPPDG.js → chunk-UUT5HNST.js} +121 -1
  5. package/dist/{chunk-6FIB72KX.js → chunk-YEXQDI3J.js} +63 -1
  6. package/dist/{chunk-GDIZWDBY.js → chunk-ZPQOE7KD.js} +78 -1
  7. package/dist/{code-DaRvff2v.d.cts → code-BK-x8hVx.d.cts} +51 -2
  8. package/dist/{code-DaRvff2v.d.ts → code-BK-x8hVx.d.ts} +51 -2
  9. package/dist/{data-C4lCByXw.d.cts → data-CFeS9kes.d.cts} +35 -2
  10. package/dist/{data-C4lCByXw.d.ts → data-CFeS9kes.d.ts} +35 -2
  11. package/dist/index.cjs +339 -0
  12. package/dist/index.d.cts +4 -4
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +4 -4
  15. package/dist/{network-D7Epuerc.d.cts → network-DfY5Ikvr.d.cts} +34 -2
  16. package/dist/{network-D7Epuerc.d.ts → network-DfY5Ikvr.d.ts} +34 -2
  17. package/dist/tools/code.cjs +120 -0
  18. package/dist/tools/code.d.cts +1 -1
  19. package/dist/tools/code.d.ts +1 -1
  20. package/dist/tools/code.js +1 -1
  21. package/dist/tools/data.cjs +62 -0
  22. package/dist/tools/data.d.cts +1 -1
  23. package/dist/tools/data.d.ts +1 -1
  24. package/dist/tools/data.js +1 -1
  25. package/dist/tools/network.cjs +80 -0
  26. package/dist/tools/network.d.cts +1 -1
  27. package/dist/tools/network.d.ts +1 -1
  28. package/dist/tools/network.js +1 -1
  29. package/dist/tools/units.cjs +77 -0
  30. package/dist/tools/units.d.cts +1 -1
  31. package/dist/tools/units.d.ts +1 -1
  32. package/dist/tools/units.js +1 -1
  33. package/dist/{units-DQYLZd1n.d.ts → units-BhoxdHhs.d.cts} +42 -2
  34. package/dist/{units-DQYLZd1n.d.cts → units-BhoxdHhs.d.ts} +42 -2
  35. package/package.json +1 -1
@@ -2689,9 +2689,128 @@ function detectRedos(pattern) {
2689
2689
  findings: unique
2690
2690
  };
2691
2691
  }
2692
+ var DEFAULT_COMMIT_TYPES = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"];
2693
+ var _DEFAULT_MAX_HEADER_LENGTH = 100;
2694
+ var _COMMIT_HEADER_RE = /^([A-Za-z][A-Za-z0-9-]*)(\(([^()]*)\))?(!)?: (.+)$/;
2695
+ var _COMMIT_FOOTER_LINE_RE = /^([A-Za-z][A-Za-z0-9-]*|BREAKING CHANGE)(: ?| #)(.*)$/;
2696
+ var _COMMIT_BREAKING_LOOKALIKE_RE = /^([A-Za-z][A-Za-z -]*?)(: | #)(.*)$/;
2697
+ var _COMMIT_BREAKING_TOKEN_RE = /^breaking[- ]change$/i;
2698
+ function lintConventionalCommit(message, options = {}) {
2699
+ if (typeof message !== "string" || message.trim() === "") {
2700
+ return { error: "message is required" };
2701
+ }
2702
+ if (message.length > 2e4) {
2703
+ return { error: "message too long (max 20,000 chars)" };
2704
+ }
2705
+ const types = options.types && options.types.length > 0 ? options.types : DEFAULT_COMMIT_TYPES;
2706
+ const maxHeaderLength = options.maxHeaderLength ?? _DEFAULT_MAX_HEADER_LENGTH;
2707
+ const findings = [];
2708
+ const lines = message.replace(/\r\n/g, "\n").split("\n");
2709
+ const header = lines[0];
2710
+ const match = header.match(_COMMIT_HEADER_RE);
2711
+ const parsed = {
2712
+ header,
2713
+ type: null,
2714
+ scope: null,
2715
+ breaking: false,
2716
+ description: null,
2717
+ body: null,
2718
+ footers: []
2719
+ };
2720
+ if (!match) {
2721
+ findings.push({
2722
+ rule: "header-format",
2723
+ severity: "error",
2724
+ message: "Header must match '<type>[(scope)][!]: <description>', e.g. 'feat(auth): add OAuth2 login'. A single space must follow the colon."
2725
+ });
2726
+ return { message, valid: false, parsed, findings };
2727
+ }
2728
+ const [, type, scopeGroup, scope, bang, description] = match;
2729
+ parsed.type = type;
2730
+ if (scopeGroup !== void 0) {
2731
+ const scopeContent = (scope ?? "").trim();
2732
+ if (scopeContent === "") {
2733
+ findings.push({ rule: "scope-empty", severity: "error", message: "Scope parentheses are present but empty; either remove the parentheses or put a scope inside them, e.g. fix(parser):." });
2734
+ } else {
2735
+ parsed.scope = scopeContent;
2736
+ }
2737
+ }
2738
+ const trimmedDescription = description.trim();
2739
+ if (trimmedDescription === "") {
2740
+ findings.push({ rule: "subject-empty", severity: "error", message: "The description after the colon must not be empty." });
2741
+ } else {
2742
+ parsed.description = trimmedDescription;
2743
+ if (trimmedDescription.endsWith(".")) {
2744
+ findings.push({ rule: "subject-full-stop", severity: "warning", message: "The description should not end with a period." });
2745
+ }
2746
+ }
2747
+ if (!types.includes(type.toLowerCase())) {
2748
+ findings.push({
2749
+ rule: "type-unknown",
2750
+ severity: "warning",
2751
+ message: `'${type}' is not one of the recognized types (${types.join(", ")}). This is only a convention, not a spec requirement, so a custom type is fine if your team has agreed on it.`
2752
+ });
2753
+ }
2754
+ if (type !== type.toLowerCase()) {
2755
+ findings.push({ rule: "type-case", severity: "warning", message: "The type is conventionally lower-case. The spec itself is not case-sensitive about this, but nearly every tool and team defaults to lower-case." });
2756
+ }
2757
+ if (header.length > maxHeaderLength) {
2758
+ findings.push({ rule: "header-max-length", severity: "warning", message: `Header is ${header.length} characters, longer than the recommended maximum of ${maxHeaderLength}.` });
2759
+ }
2760
+ let breaking = bang === "!";
2761
+ if (lines.length > 1) {
2762
+ if (lines[1].trim() !== "") {
2763
+ findings.push({ rule: "missing-blank-line-before-body", severity: "error", message: "A blank line must separate the header from the body or footer." });
2764
+ }
2765
+ const rest = lines.slice(1).join("\n");
2766
+ const paragraphs = rest.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p !== "");
2767
+ let footerParagraph = null;
2768
+ if (paragraphs.length > 0) {
2769
+ const last = paragraphs[paragraphs.length - 1];
2770
+ const lastLines = last.split("\n");
2771
+ if (lastLines.every((l) => _COMMIT_FOOTER_LINE_RE.test(l.trim()))) {
2772
+ footerParagraph = last;
2773
+ paragraphs.pop();
2774
+ }
2775
+ }
2776
+ parsed.body = paragraphs.length > 0 ? paragraphs.join("\n\n") : null;
2777
+ if (footerParagraph) {
2778
+ for (const line of footerParagraph.split("\n")) {
2779
+ const fm = line.trim().match(_COMMIT_FOOTER_LINE_RE);
2780
+ if (!fm) continue;
2781
+ const [, token, , value] = fm;
2782
+ parsed.footers.push({ token, value: value.trim() });
2783
+ }
2784
+ }
2785
+ for (const f of parsed.footers) {
2786
+ if (_COMMIT_BREAKING_TOKEN_RE.test(f.token) && f.token !== "BREAKING CHANGE" && f.token !== "BREAKING-CHANGE") {
2787
+ findings.push({ rule: "breaking-change-casing", severity: "error", message: `Found '${f.token}:' as a footer, but the spec requires the breaking-change token to be exactly 'BREAKING CHANGE' or 'BREAKING-CHANGE' (uppercase).` });
2788
+ }
2789
+ }
2790
+ for (const p of paragraphs) {
2791
+ for (const line of p.split("\n")) {
2792
+ const bm = line.trim().match(_COMMIT_BREAKING_LOOKALIKE_RE);
2793
+ if (bm && _COMMIT_BREAKING_TOKEN_RE.test(bm[1]) && bm[1] !== "BREAKING CHANGE") {
2794
+ findings.push({ rule: "breaking-change-casing", severity: "error", message: `Found '${bm[1]}' near the end of the message, but it wasn't recognized as a breaking-change footer. The spec requires the exact uppercase token 'BREAKING CHANGE' (or 'BREAKING-CHANGE'), immediately followed by ': '.` });
2795
+ }
2796
+ }
2797
+ }
2798
+ }
2799
+ const breakingFooter = parsed.footers.find((f) => f.token === "BREAKING CHANGE" || f.token === "BREAKING-CHANGE");
2800
+ if (breakingFooter) {
2801
+ breaking = true;
2802
+ if (breakingFooter.value === "") {
2803
+ findings.push({ rule: "breaking-change-empty", severity: "error", message: "A 'BREAKING CHANGE:' footer must be followed by a description of the breaking change." });
2804
+ }
2805
+ }
2806
+ parsed.breaking = breaking;
2807
+ const valid = !findings.some((f) => f.severity === "error");
2808
+ return { message, valid, parsed, findings };
2809
+ }
2692
2810
 
2693
2811
  exports.ALL_FLAGS = ALL_FLAGS;
2694
2812
  exports.CHEATSHEET = CHEATSHEET;
2813
+ exports.DEFAULT_COMMIT_TYPES = DEFAULT_COMMIT_TYPES;
2695
2814
  exports.MIME_TABLE = MIME_TABLE;
2696
2815
  exports.OPERATIONS = OPERATIONS;
2697
2816
  exports.SQL_DEFAULT_OPTIONS = SQL_DEFAULT_OPTIONS;
@@ -2716,6 +2835,7 @@ exports.getHtmlStats = getHtmlStats;
2716
2835
  exports.getJsStats = getJsStats;
2717
2836
  exports.getMethodColor = getMethodColor;
2718
2837
  exports.isValidTag = isValidTag;
2838
+ exports.lintConventionalCommit = lintConventionalCommit;
2719
2839
  exports.lookupMime = lookupMime;
2720
2840
  exports.minifyCss = minifyCss;
2721
2841
  exports.minifyGql = minifyGql;
@@ -1 +1 @@
1
- export { A as ALL_FLAGS, a as ApiEndpoint, b as ApiInfo, C as CHEATSHEET, d as CheatsheetEntry, e as CssResult, D as DockerImageRef, E as EnvEntry, f as EnvParseResult, G as GitCommandConfig, g as GitCommandResult, h as GitOperation, i as GithubUrlInfo, j as GithubUrlType, k as GqlFormatResult, H as HtmlFormatResult, l as HtmlMinifyOptions, m as HtmlMinifyResult, J as JsMinifyOptions, n as JsMinifyResult, M as MIME_TABLE, o as MatchResult, p as MimeEntry, q as MimeLookupResult, O as OPERATIONS, P as ParsedSpec, R as RedosFinding, r as RedosResult, s as RedosSeverity, t as RegexError, u as RegexFlag, v as RegexMatch, w as RegexResult, x as RegexSuccess, S as SQL_DEFAULT_OPTIONS, y as Segment, z as SpecVersion, B as SqlDialect, F as SqlFormatOptions, T as TestPatternResult, I as buildDockerPull, K as buildDockerRun, L as buildGitCommand, N as collapseHtmlWhitespace, Q as collapseJsWhitespace, U as countProperties, V as countRules, W as detectDialect, X as detectOperationType, Y as detectRedos, Z as envToExport, _ as envToJson, $ as formatCss, a0 as formatGql, a1 as formatHtml, a2 as formatSql, a3 as getEndpointsByTag, a4 as getHtmlStats, a5 as getJsStats, a6 as getMethodColor, a7 as isValidTag, a8 as lookupMime, a9 as minifyCss, aa as minifyGql, ab as minifyHtml, ac as minifyJs, ad as minifySql, ae as normalizeRef, af as parseDockerImage, ag as parseEnv, ah as parseGitCommand, ai as parseGithubUrl, aj as parseSpec, ak as removeConsoleCalls, al as removeEmptyAttributes, am as removeHtmlComments, an as removeJsComments, ao as removeRedundantAttributes, ap as searchCheatsheet, aq as searchEndpoints, ar as splitStatements, as as testPattern, at as testRegex, au as validateEnvKey } from '../code-DaRvff2v.cjs';
1
+ export { A as ALL_FLAGS, a as ApiEndpoint, b as ApiInfo, C as CHEATSHEET, d as CheatsheetEntry, e as ConventionalCommitFinding, f as ConventionalCommitFooter, g as ConventionalCommitOptions, h as ConventionalCommitParsed, i as ConventionalCommitResult, j as ConventionalCommitSeverity, k as CssResult, D as DEFAULT_COMMIT_TYPES, l as DockerImageRef, E as EnvEntry, m as EnvParseResult, G as GitCommandConfig, n as GitCommandResult, o as GitOperation, p as GithubUrlInfo, q as GithubUrlType, r as GqlFormatResult, H as HtmlFormatResult, s as HtmlMinifyOptions, t as HtmlMinifyResult, J as JsMinifyOptions, u as JsMinifyResult, M as MIME_TABLE, v as MatchResult, w as MimeEntry, x as MimeLookupResult, O as OPERATIONS, P as ParsedSpec, R as RedosFinding, y as RedosResult, z as RedosSeverity, B as RegexError, F as RegexFlag, I as RegexMatch, K as RegexResult, L as RegexSuccess, S as SQL_DEFAULT_OPTIONS, N as Segment, Q as SpecVersion, T as SqlDialect, U as SqlFormatOptions, V as TestPatternResult, W as buildDockerPull, X as buildDockerRun, Y as buildGitCommand, Z as collapseHtmlWhitespace, _ as collapseJsWhitespace, $ as countProperties, a0 as countRules, a1 as detectDialect, a2 as detectOperationType, a3 as detectRedos, a4 as envToExport, a5 as envToJson, a6 as formatCss, a7 as formatGql, a8 as formatHtml, a9 as formatSql, aa as getEndpointsByTag, ab as getHtmlStats, ac as getJsStats, ad as getMethodColor, ae as isValidTag, af as lintConventionalCommit, ag as lookupMime, ah as minifyCss, ai as minifyGql, aj as minifyHtml, ak as minifyJs, al as minifySql, am as normalizeRef, an as parseDockerImage, ao as parseEnv, ap as parseGitCommand, aq as parseGithubUrl, ar as parseSpec, as as removeConsoleCalls, at as removeEmptyAttributes, au as removeHtmlComments, av as removeJsComments, aw as removeRedundantAttributes, ax as searchCheatsheet, ay as searchEndpoints, az as splitStatements, aA as testPattern, aB as testRegex, aC as validateEnvKey } from '../code-BK-x8hVx.cjs';
@@ -1 +1 @@
1
- export { A as ALL_FLAGS, a as ApiEndpoint, b as ApiInfo, C as CHEATSHEET, d as CheatsheetEntry, e as CssResult, D as DockerImageRef, E as EnvEntry, f as EnvParseResult, G as GitCommandConfig, g as GitCommandResult, h as GitOperation, i as GithubUrlInfo, j as GithubUrlType, k as GqlFormatResult, H as HtmlFormatResult, l as HtmlMinifyOptions, m as HtmlMinifyResult, J as JsMinifyOptions, n as JsMinifyResult, M as MIME_TABLE, o as MatchResult, p as MimeEntry, q as MimeLookupResult, O as OPERATIONS, P as ParsedSpec, R as RedosFinding, r as RedosResult, s as RedosSeverity, t as RegexError, u as RegexFlag, v as RegexMatch, w as RegexResult, x as RegexSuccess, S as SQL_DEFAULT_OPTIONS, y as Segment, z as SpecVersion, B as SqlDialect, F as SqlFormatOptions, T as TestPatternResult, I as buildDockerPull, K as buildDockerRun, L as buildGitCommand, N as collapseHtmlWhitespace, Q as collapseJsWhitespace, U as countProperties, V as countRules, W as detectDialect, X as detectOperationType, Y as detectRedos, Z as envToExport, _ as envToJson, $ as formatCss, a0 as formatGql, a1 as formatHtml, a2 as formatSql, a3 as getEndpointsByTag, a4 as getHtmlStats, a5 as getJsStats, a6 as getMethodColor, a7 as isValidTag, a8 as lookupMime, a9 as minifyCss, aa as minifyGql, ab as minifyHtml, ac as minifyJs, ad as minifySql, ae as normalizeRef, af as parseDockerImage, ag as parseEnv, ah as parseGitCommand, ai as parseGithubUrl, aj as parseSpec, ak as removeConsoleCalls, al as removeEmptyAttributes, am as removeHtmlComments, an as removeJsComments, ao as removeRedundantAttributes, ap as searchCheatsheet, aq as searchEndpoints, ar as splitStatements, as as testPattern, at as testRegex, au as validateEnvKey } from '../code-DaRvff2v.js';
1
+ export { A as ALL_FLAGS, a as ApiEndpoint, b as ApiInfo, C as CHEATSHEET, d as CheatsheetEntry, e as ConventionalCommitFinding, f as ConventionalCommitFooter, g as ConventionalCommitOptions, h as ConventionalCommitParsed, i as ConventionalCommitResult, j as ConventionalCommitSeverity, k as CssResult, D as DEFAULT_COMMIT_TYPES, l as DockerImageRef, E as EnvEntry, m as EnvParseResult, G as GitCommandConfig, n as GitCommandResult, o as GitOperation, p as GithubUrlInfo, q as GithubUrlType, r as GqlFormatResult, H as HtmlFormatResult, s as HtmlMinifyOptions, t as HtmlMinifyResult, J as JsMinifyOptions, u as JsMinifyResult, M as MIME_TABLE, v as MatchResult, w as MimeEntry, x as MimeLookupResult, O as OPERATIONS, P as ParsedSpec, R as RedosFinding, y as RedosResult, z as RedosSeverity, B as RegexError, F as RegexFlag, I as RegexMatch, K as RegexResult, L as RegexSuccess, S as SQL_DEFAULT_OPTIONS, N as Segment, Q as SpecVersion, T as SqlDialect, U as SqlFormatOptions, V as TestPatternResult, W as buildDockerPull, X as buildDockerRun, Y as buildGitCommand, Z as collapseHtmlWhitespace, _ as collapseJsWhitespace, $ as countProperties, a0 as countRules, a1 as detectDialect, a2 as detectOperationType, a3 as detectRedos, a4 as envToExport, a5 as envToJson, a6 as formatCss, a7 as formatGql, a8 as formatHtml, a9 as formatSql, aa as getEndpointsByTag, ab as getHtmlStats, ac as getJsStats, ad as getMethodColor, ae as isValidTag, af as lintConventionalCommit, ag as lookupMime, ah as minifyCss, ai as minifyGql, aj as minifyHtml, ak as minifyJs, al as minifySql, am as normalizeRef, an as parseDockerImage, ao as parseEnv, ap as parseGitCommand, aq as parseGithubUrl, ar as parseSpec, as as removeConsoleCalls, at as removeEmptyAttributes, au as removeHtmlComments, av as removeJsComments, aw as removeRedundantAttributes, ax as searchCheatsheet, ay as searchEndpoints, az as splitStatements, aA as testPattern, aB as testRegex, aC as validateEnvKey } from '../code-BK-x8hVx.js';
@@ -1,2 +1,2 @@
1
- export { ALL_FLAGS, CHEATSHEET, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testPattern, testRegex, validateEnvKey } from '../chunk-LXKIPPDG.js';
1
+ export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lintConventionalCommit, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testPattern, testRegex, validateEnvKey } from '../chunk-UUT5HNST.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -1373,6 +1373,67 @@ function parseFrontMatter(input) {
1373
1373
  }
1374
1374
  return { frontMatter, body: afterClose, hasFrontMatter: true, raw };
1375
1375
  }
1376
+ function stripInlineMarkdown(text) {
1377
+ return text.replace(/(\*\*\*|___)(.+?)\1/g, "$2").replace(/(\*\*|__)(.+?)\1/g, "$2").replace(/(\*|_)(.+?)\1/g, "$2").replace(/`([^`]+)`/g, "$1").replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").trim();
1378
+ }
1379
+ function slugifyHeading(text, seen) {
1380
+ let slug = text.toLowerCase().trim().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-");
1381
+ const count = seen.get(slug) ?? 0;
1382
+ seen.set(slug, count + 1);
1383
+ if (count > 0) slug = `${slug}-${count}`;
1384
+ return slug;
1385
+ }
1386
+ function generateMarkdownToc(markdown, options = {}) {
1387
+ if (typeof markdown !== "string" || markdown.trim() === "") {
1388
+ return { error: "markdown is required" };
1389
+ }
1390
+ const minLevel = options.minLevel ?? 1;
1391
+ const maxLevel = options.maxLevel ?? 6;
1392
+ if (!Number.isInteger(minLevel) || !Number.isInteger(maxLevel) || minLevel < 1 || minLevel > 6 || maxLevel < 1 || maxLevel > 6 || minLevel > maxLevel) {
1393
+ return { error: "minLevel and maxLevel must be integers between 1 and 6, with minLevel <= maxLevel" };
1394
+ }
1395
+ const lines = markdown.replace(/\r\n/g, "\n").split("\n");
1396
+ const entries = [];
1397
+ const seen = /* @__PURE__ */ new Map();
1398
+ let inFence = false;
1399
+ let fenceMarker = "";
1400
+ for (const line of lines) {
1401
+ const fenceMatch = line.match(/^\s*(```+|~~~+)/);
1402
+ if (fenceMatch) {
1403
+ if (!inFence) {
1404
+ inFence = true;
1405
+ fenceMarker = fenceMatch[1][0];
1406
+ } else if (fenceMatch[1][0] === fenceMarker) {
1407
+ inFence = false;
1408
+ }
1409
+ continue;
1410
+ }
1411
+ if (inFence) continue;
1412
+ const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*#*\s*$/);
1413
+ if (!headingMatch) continue;
1414
+ const level = headingMatch[1].length;
1415
+ const text = stripInlineMarkdown(headingMatch[2]);
1416
+ if (text === "") continue;
1417
+ const slug = slugifyHeading(text, seen);
1418
+ if (level < minLevel || level > maxLevel) continue;
1419
+ entries.push({ level, text, slug });
1420
+ }
1421
+ if (entries.length === 0) {
1422
+ return { error: "No headings found in the given level range" };
1423
+ }
1424
+ const baseLevel = Math.min(...entries.map((e) => e.level));
1425
+ const counters = [0, 0, 0, 0, 0, 0, 0];
1426
+ const tocLines = entries.map((e) => {
1427
+ const indent = " ".repeat(e.level - baseLevel);
1428
+ if (options.ordered) {
1429
+ counters[e.level] = (counters[e.level] ?? 0) + 1;
1430
+ for (let l = e.level + 1; l < counters.length; l++) counters[l] = 0;
1431
+ return `${indent}${counters[e.level]}. [${e.text}](#${e.slug})`;
1432
+ }
1433
+ return `${indent}- [${e.text}](#${e.slug})`;
1434
+ });
1435
+ return { toc: tocLines.join("\n"), entries };
1436
+ }
1376
1437
 
1377
1438
  exports.convertSubtitles = convertSubtitles;
1378
1439
  exports.csvToJson = csvToJson;
@@ -1385,6 +1446,7 @@ exports.formatNdjson = formatNdjson;
1385
1446
  exports.formatSubtitleTimestamp = formatSubtitleTimestamp;
1386
1447
  exports.formatToml = formatToml;
1387
1448
  exports.formatXml = formatXml;
1449
+ exports.generateMarkdownToc = generateMarkdownToc;
1388
1450
  exports.getSection = getSection;
1389
1451
  exports.getSectionNames = getSectionNames;
1390
1452
  exports.getTomlStats = getTomlStats;
@@ -1 +1 @@
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
+ 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, M as MarkdownTocEntry, g as MarkdownTocOptions, h as MarkdownTocResult, N as NdjsonLineResult, i as NdjsonValidateResult, P as ParseOptions, j as ParsedIni, k as ParsedSubtitles, S as SubtitleCue, l as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, m as XmlToJsonOptions, n as convertSubtitles, o as csvToJson, p as detectDelimiter, q as detectSubtitleFormat, r as diffEnvExample, s as envToExport, t as envToJson, u as formatNdjson, v as formatSubtitleTimestamp, w as formatToml, x as formatXml, y as generateMarkdownToc, z as getSection, A as getSectionNames, B as getTomlStats, D as getXmlStats, G as getYamlStats, H as iniToJson, J as jsonArrayToNdjson, K as jsonToIni, L as jsonToToml, O as jsonToXml, Q as minifyNdjson, R as minifyToml, U as minifyXml, W as ndjsonToJsonArray, Y as parseCsv, Z as parseEnv, _ as parseFrontMatter, $ as parseIni, a0 as parseSubtitleTimestamp, a1 as parseSubtitles, a2 as parseXmlToObject, a3 as serializeSubtitles, a4 as shiftSubtitles, a5 as stringifyIni, a6 as toCsvString, a7 as tomlToJson, a8 as validateEnvKey, a9 as validateIni, aa as validateNdjson, ab as validateToml, ac as validateXml, ad as validateYaml, ae as xmlToJson } from '../data-CFeS9kes.cjs';
@@ -1 +1 @@
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
+ 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, M as MarkdownTocEntry, g as MarkdownTocOptions, h as MarkdownTocResult, N as NdjsonLineResult, i as NdjsonValidateResult, P as ParseOptions, j as ParsedIni, k as ParsedSubtitles, S as SubtitleCue, l as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, m as XmlToJsonOptions, n as convertSubtitles, o as csvToJson, p as detectDelimiter, q as detectSubtitleFormat, r as diffEnvExample, s as envToExport, t as envToJson, u as formatNdjson, v as formatSubtitleTimestamp, w as formatToml, x as formatXml, y as generateMarkdownToc, z as getSection, A as getSectionNames, B as getTomlStats, D as getXmlStats, G as getYamlStats, H as iniToJson, J as jsonArrayToNdjson, K as jsonToIni, L as jsonToToml, O as jsonToXml, Q as minifyNdjson, R as minifyToml, U as minifyXml, W as ndjsonToJsonArray, Y as parseCsv, Z as parseEnv, _ as parseFrontMatter, $ as parseIni, a0 as parseSubtitleTimestamp, a1 as parseSubtitles, a2 as parseXmlToObject, a3 as serializeSubtitles, a4 as shiftSubtitles, a5 as stringifyIni, a6 as toCsvString, a7 as tomlToJson, a8 as validateEnvKey, a9 as validateIni, aa as validateNdjson, ab as validateToml, ac as validateXml, ad as validateYaml, ae as xmlToJson } from '../data-CFeS9kes.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, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson } from '../chunk-6FIB72KX.js';
1
+ export { convertSubtitles, csvToJson, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, generateMarkdownToc, 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-YEXQDI3J.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -1777,6 +1777,84 @@ function buildCacheControl(options = {}) {
1777
1777
  const snippet = `Cache-Control: ${header}`;
1778
1778
  return { header, headerName: "Cache-Control", snippet, directives, warnings };
1779
1779
  }
1780
+ var REFERRER_POLICY_VALUES = [
1781
+ "no-referrer",
1782
+ "no-referrer-when-downgrade",
1783
+ "origin",
1784
+ "origin-when-cross-origin",
1785
+ "same-origin",
1786
+ "strict-origin",
1787
+ "strict-origin-when-cross-origin",
1788
+ "unsafe-url"
1789
+ ];
1790
+ var _REFERRER_POLICY_INFO = {
1791
+ "no-referrer": {
1792
+ explanation: "Never sends the Referer header, on any request. The strictest option; the destination learns nothing about where the request came from.",
1793
+ leaksPathAndQuery: false,
1794
+ sentOnDowngrade: false
1795
+ },
1796
+ "no-referrer-when-downgrade": {
1797
+ explanation: "Sends the full URL (origin, path, and query string) for same-security-level or upgrading requests, but omits the header entirely when navigating from HTTPS to HTTP. This was the legacy browser default before strict-origin-when-cross-origin.",
1798
+ leaksPathAndQuery: true,
1799
+ sentOnDowngrade: false
1800
+ },
1801
+ origin: {
1802
+ explanation: "Sends only the origin (scheme, host, and port) on every request, same-origin or cross-origin, including on a downgrade. The path and query string are always stripped.",
1803
+ leaksPathAndQuery: false,
1804
+ sentOnDowngrade: true
1805
+ },
1806
+ "origin-when-cross-origin": {
1807
+ explanation: "Sends the full URL for same-origin requests, but only the origin for cross-origin requests. Still sends the origin on a downgrade.",
1808
+ leaksPathAndQuery: true,
1809
+ sentOnDowngrade: true
1810
+ },
1811
+ "same-origin": {
1812
+ explanation: "Sends the full URL for same-origin requests, and no Referer header at all for cross-origin requests.",
1813
+ leaksPathAndQuery: true,
1814
+ sentOnDowngrade: false
1815
+ },
1816
+ "strict-origin": {
1817
+ explanation: "Sends only the origin, and only when the security level stays the same or improves (HTTPS to HTTPS, or HTTP to anything). Nothing is sent on a downgrade from HTTPS to HTTP.",
1818
+ leaksPathAndQuery: false,
1819
+ sentOnDowngrade: false
1820
+ },
1821
+ "strict-origin-when-cross-origin": {
1822
+ explanation: "Sends the full URL for same-origin requests, only the origin for cross-origin requests at the same or better security level, and nothing at all on a downgrade. This is the current browser default when no policy is set.",
1823
+ leaksPathAndQuery: true,
1824
+ sentOnDowngrade: false
1825
+ },
1826
+ "unsafe-url": {
1827
+ explanation: "Always sends the full URL, including path and query string, on every request, even on a downgrade from HTTPS to HTTP. Generally discouraged: query strings can carry session tokens or other sensitive data that then leaks to third-party destinations and to the network on an insecure connection.",
1828
+ leaksPathAndQuery: true,
1829
+ sentOnDowngrade: true
1830
+ }
1831
+ };
1832
+ function buildReferrerPolicy(policies) {
1833
+ const list = Array.isArray(policies) ? policies : [policies];
1834
+ const trimmed = list.map((p) => typeof p === "string" ? p.trim() : "").filter((p) => p !== "");
1835
+ if (trimmed.length === 0) {
1836
+ return { error: "At least one policy value is required" };
1837
+ }
1838
+ const entries = [];
1839
+ for (const value of trimmed) {
1840
+ if (!REFERRER_POLICY_VALUES.includes(value)) {
1841
+ return { error: `'${value}' is not a valid Referrer-Policy value. Valid values: ${REFERRER_POLICY_VALUES.join(", ")}` };
1842
+ }
1843
+ entries.push({ value, ..._REFERRER_POLICY_INFO[value] });
1844
+ }
1845
+ const warnings = [];
1846
+ const last = entries[entries.length - 1];
1847
+ if (last.value === "unsafe-url") {
1848
+ warnings.push("unsafe-url sends the full URL, including query strings, on every request, even over an insecure downgrade. Prefer strict-origin-when-cross-origin unless you have a specific reason to leak full URLs.");
1849
+ }
1850
+ if (entries.length > 1 && entries.some((e, i) => i !== entries.length - 1 && e.value === last.value)) {
1851
+ warnings.push("The same policy value appears more than once in the fallback chain, which has no effect beyond the first occurrence.");
1852
+ }
1853
+ const header = entries.map((e) => e.value).join(", ");
1854
+ const snippet = `Referrer-Policy: ${header}`;
1855
+ const metaTag = `<meta name="referrer" content="${last.value}">`;
1856
+ return { header, headerName: "Referrer-Policy", snippet, metaTag, policies: entries, warnings };
1857
+ }
1780
1858
  function isValidIpv6HexGroup(g) {
1781
1859
  return /^[0-9a-fA-F]{1,4}$/.test(g);
1782
1860
  }
@@ -1868,11 +1946,13 @@ function parseIpv6Address(input) {
1868
1946
 
1869
1947
  exports.DNS_RECORD_TYPES = DNS_RECORD_TYPES;
1870
1948
  exports.HTTP_HEADERS = HTTP_HEADERS;
1949
+ exports.REFERRER_POLICY_VALUES = REFERRER_POLICY_VALUES;
1871
1950
  exports.STATUS_CODES = STATUS_CODES;
1872
1951
  exports.buildCacheControl = buildCacheControl;
1873
1952
  exports.buildDnsQueryUrl = buildDnsQueryUrl;
1874
1953
  exports.buildGeoUrl = buildGeoUrl;
1875
1954
  exports.buildMapUrl = buildMapUrl;
1955
+ exports.buildReferrerPolicy = buildReferrerPolicy;
1876
1956
  exports.countryCodeToFlag = countryCodeToFlag;
1877
1957
  exports.formatCoordinates = formatCoordinates;
1878
1958
  exports.formatTtl = formatTtl;
@@ -1 +1 @@
1
- export { C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, D as DNS_RECORD_TYPES, c as DnsRecord, d as DnsRecordType, e as DnsResponse, G as GeoResult, H as HTTP_HEADERS, f as HarEntry, g as HarParseResult, h as HarSummary, i as HeaderCategory, j as HttpHeader, I as Ipv6AddressType, k as Ipv6ParseResult, P as ParsedDnsResult, l as ParsedGeoResult, R as RobotsGroup, m as RobotsIssue, o as RobotsRule, p as RobotsValidationResult, S as STATUS_CODES, q as SitemapIndexEntry, r as SitemapIssue, s as SitemapUrlEntry, t as SitemapValidationResult, u as StatusCode, U as UaDeviceType, v as UserAgentInfo, w as buildCacheControl, x as buildDnsQueryUrl, y as buildGeoUrl, z as buildMapUrl, A as countryCodeToFlag, B as formatCoordinates, E as formatTtl, F as getByCategory, J as getHeader, K as getHeadersByCategory, L as getStatusByCategory, M as getStatusCode, N as isClientError, O as isServerError, Q as isSuccess, T as isValidIp, V as isValidIpv4, W as isValidIpv6, X as parseDnsResponse, Y as parseGeoResponse, Z as parseHar, _ as parseIpv6Address, $ as parseUserAgent, a0 as searchHeaders, a1 as searchStatusCodes, a2 as statusCodeToText, a3 as typeNumberToLabel, a4 as validateDomain, a5 as validateHeaderName, a6 as validateHeaderValue, a7 as validateRobotsTxt, a8 as validateSitemap } from '../network-D7Epuerc.cjs';
1
+ export { C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, D as DNS_RECORD_TYPES, c as DnsRecord, d as DnsRecordType, e as DnsResponse, G as GeoResult, H as HTTP_HEADERS, f as HarEntry, g as HarParseResult, h as HarSummary, i as HeaderCategory, j as HttpHeader, I as Ipv6AddressType, k as Ipv6ParseResult, P as ParsedDnsResult, l as ParsedGeoResult, R as REFERRER_POLICY_VALUES, m as ReferrerPolicyEntry, o as ReferrerPolicyResult, p as ReferrerPolicyValue, q as RobotsGroup, r as RobotsIssue, s as RobotsRule, t as RobotsValidationResult, S as STATUS_CODES, u as SitemapIndexEntry, v as SitemapIssue, w as SitemapUrlEntry, x as SitemapValidationResult, y as StatusCode, U as UaDeviceType, z as UserAgentInfo, A as buildCacheControl, B as buildDnsQueryUrl, E as buildGeoUrl, F as buildMapUrl, J as buildReferrerPolicy, K as countryCodeToFlag, L as formatCoordinates, M as formatTtl, N as getByCategory, O as getHeader, Q as getHeadersByCategory, T as getStatusByCategory, V as getStatusCode, W as isClientError, X as isServerError, Y as isSuccess, Z as isValidIp, _ as isValidIpv4, $ as isValidIpv6, a0 as parseDnsResponse, a1 as parseGeoResponse, a2 as parseHar, a3 as parseIpv6Address, a4 as parseUserAgent, a5 as searchHeaders, a6 as searchStatusCodes, a7 as statusCodeToText, a8 as typeNumberToLabel, a9 as validateDomain, aa as validateHeaderName, ab as validateHeaderValue, ac as validateRobotsTxt, ad as validateSitemap } from '../network-DfY5Ikvr.cjs';
@@ -1 +1 @@
1
- export { C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, D as DNS_RECORD_TYPES, c as DnsRecord, d as DnsRecordType, e as DnsResponse, G as GeoResult, H as HTTP_HEADERS, f as HarEntry, g as HarParseResult, h as HarSummary, i as HeaderCategory, j as HttpHeader, I as Ipv6AddressType, k as Ipv6ParseResult, P as ParsedDnsResult, l as ParsedGeoResult, R as RobotsGroup, m as RobotsIssue, o as RobotsRule, p as RobotsValidationResult, S as STATUS_CODES, q as SitemapIndexEntry, r as SitemapIssue, s as SitemapUrlEntry, t as SitemapValidationResult, u as StatusCode, U as UaDeviceType, v as UserAgentInfo, w as buildCacheControl, x as buildDnsQueryUrl, y as buildGeoUrl, z as buildMapUrl, A as countryCodeToFlag, B as formatCoordinates, E as formatTtl, F as getByCategory, J as getHeader, K as getHeadersByCategory, L as getStatusByCategory, M as getStatusCode, N as isClientError, O as isServerError, Q as isSuccess, T as isValidIp, V as isValidIpv4, W as isValidIpv6, X as parseDnsResponse, Y as parseGeoResponse, Z as parseHar, _ as parseIpv6Address, $ as parseUserAgent, a0 as searchHeaders, a1 as searchStatusCodes, a2 as statusCodeToText, a3 as typeNumberToLabel, a4 as validateDomain, a5 as validateHeaderName, a6 as validateHeaderValue, a7 as validateRobotsTxt, a8 as validateSitemap } from '../network-D7Epuerc.js';
1
+ export { C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, D as DNS_RECORD_TYPES, c as DnsRecord, d as DnsRecordType, e as DnsResponse, G as GeoResult, H as HTTP_HEADERS, f as HarEntry, g as HarParseResult, h as HarSummary, i as HeaderCategory, j as HttpHeader, I as Ipv6AddressType, k as Ipv6ParseResult, P as ParsedDnsResult, l as ParsedGeoResult, R as REFERRER_POLICY_VALUES, m as ReferrerPolicyEntry, o as ReferrerPolicyResult, p as ReferrerPolicyValue, q as RobotsGroup, r as RobotsIssue, s as RobotsRule, t as RobotsValidationResult, S as STATUS_CODES, u as SitemapIndexEntry, v as SitemapIssue, w as SitemapUrlEntry, x as SitemapValidationResult, y as StatusCode, U as UaDeviceType, z as UserAgentInfo, A as buildCacheControl, B as buildDnsQueryUrl, E as buildGeoUrl, F as buildMapUrl, J as buildReferrerPolicy, K as countryCodeToFlag, L as formatCoordinates, M as formatTtl, N as getByCategory, O as getHeader, Q as getHeadersByCategory, T as getStatusByCategory, V as getStatusCode, W as isClientError, X as isServerError, Y as isSuccess, Z as isValidIp, _ as isValidIpv4, $ as isValidIpv6, a0 as parseDnsResponse, a1 as parseGeoResponse, a2 as parseHar, a3 as parseIpv6Address, a4 as parseUserAgent, a5 as searchHeaders, a6 as searchStatusCodes, a7 as statusCodeToText, a8 as typeNumberToLabel, a9 as validateDomain, aa as validateHeaderName, ab as validateHeaderValue, ac as validateRobotsTxt, ad as validateSitemap } from '../network-DfY5Ikvr.js';
@@ -1,2 +1,2 @@
1
- export { DNS_RECORD_TYPES, HTTP_HEADERS, STATUS_CODES, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildMapUrl, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap } from '../chunk-CSNTHZHF.js';
1
+ export { DNS_RECORD_TYPES, HTTP_HEADERS, REFERRER_POLICY_VALUES, STATUS_CODES, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildMapUrl, buildReferrerPolicy, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap } from '../chunk-3YUKLV5N.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -1648,6 +1648,82 @@ function calculateEmi(principal, annualRatePercent, tenure, tenureUnit = "years"
1648
1648
  yearlyBreakdown
1649
1649
  };
1650
1650
  }
1651
+ function calculateSavingsGoal(input) {
1652
+ const { mode, goalAmount, currentSavings, annualInterestRatePercent, monthlyContribution, months } = input;
1653
+ if (mode !== "time-to-goal" && mode !== "contribution-for-target") {
1654
+ return { error: "mode must be 'time-to-goal' or 'contribution-for-target'" };
1655
+ }
1656
+ if (!Number.isFinite(goalAmount) || goalAmount <= 0) return { error: "goalAmount must be a finite number greater than zero" };
1657
+ if (!Number.isFinite(currentSavings) || currentSavings < 0) return { error: "currentSavings must be a finite, non-negative number" };
1658
+ if (!Number.isFinite(annualInterestRatePercent) || annualInterestRatePercent < 0) {
1659
+ return { error: "annualInterestRatePercent must be a finite, non-negative number" };
1660
+ }
1661
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
1662
+ const r = annualInterestRatePercent / 100 / 12;
1663
+ if (mode === "time-to-goal") {
1664
+ if (typeof monthlyContribution !== "number" || !Number.isFinite(monthlyContribution) || monthlyContribution < 0) {
1665
+ return { error: "monthlyContribution must be a finite, non-negative number" };
1666
+ }
1667
+ let exactMonths;
1668
+ if (currentSavings >= goalAmount) {
1669
+ exactMonths = 0;
1670
+ } else if (monthlyContribution === 0) {
1671
+ if (r === 0) return { error: "monthlyContribution must be greater than zero when annualInterestRatePercent is zero, since savings would never grow toward the goal" };
1672
+ if (currentSavings <= 0) return { error: "monthlyContribution must be greater than zero when currentSavings is zero, since there is nothing to compound" };
1673
+ exactMonths = Math.log(goalAmount / currentSavings) / Math.log(1 + r);
1674
+ } else if (r === 0) {
1675
+ exactMonths = (goalAmount - currentSavings) / monthlyContribution;
1676
+ } else {
1677
+ const denom = currentSavings + monthlyContribution / r;
1678
+ const x = (goalAmount + monthlyContribution / r) / denom;
1679
+ exactMonths = Math.log(x) / Math.log(1 + r);
1680
+ }
1681
+ const monthsRounded = Math.max(0, Math.ceil(exactMonths));
1682
+ const finalBalance = r === 0 ? currentSavings + monthlyContribution * monthsRounded : currentSavings * Math.pow(1 + r, monthsRounded) + monthlyContribution * ((Math.pow(1 + r, monthsRounded) - 1) / r);
1683
+ const totalContributed2 = monthlyContribution * monthsRounded;
1684
+ const totalInterestEarned2 = finalBalance - currentSavings - totalContributed2;
1685
+ return {
1686
+ mode,
1687
+ goalAmount: round4(goalAmount),
1688
+ currentSavings: round4(currentSavings),
1689
+ annualInterestRatePercent: round4(annualInterestRatePercent),
1690
+ monthlyContribution: round4(monthlyContribution),
1691
+ months: round4(exactMonths),
1692
+ monthsRounded,
1693
+ years: round4(monthsRounded / 12),
1694
+ totalContributed: round4(totalContributed2),
1695
+ totalInterestEarned: round4(totalInterestEarned2),
1696
+ finalBalance: round4(finalBalance)
1697
+ };
1698
+ }
1699
+ if (typeof months !== "number" || !Number.isFinite(months) || !Number.isInteger(months) || months <= 0) {
1700
+ return { error: "months must be a positive integer" };
1701
+ }
1702
+ const growthOfCurrentSavings = r === 0 ? currentSavings : currentSavings * Math.pow(1 + r, months);
1703
+ let requiredMonthlyContribution;
1704
+ if (growthOfCurrentSavings >= goalAmount) {
1705
+ requiredMonthlyContribution = 0;
1706
+ } else if (r === 0) {
1707
+ requiredMonthlyContribution = (goalAmount - currentSavings) / months;
1708
+ } else {
1709
+ requiredMonthlyContribution = (goalAmount - growthOfCurrentSavings) * r / (Math.pow(1 + r, months) - 1);
1710
+ }
1711
+ const totalContributed = requiredMonthlyContribution * months;
1712
+ const totalInterestEarned = goalAmount - currentSavings - totalContributed;
1713
+ return {
1714
+ mode,
1715
+ goalAmount: round4(goalAmount),
1716
+ currentSavings: round4(currentSavings),
1717
+ annualInterestRatePercent: round4(annualInterestRatePercent),
1718
+ monthlyContribution: round4(requiredMonthlyContribution),
1719
+ months,
1720
+ monthsRounded: months,
1721
+ years: round4(months / 12),
1722
+ totalContributed: round4(totalContributed),
1723
+ totalInterestEarned: round4(totalInterestEarned),
1724
+ finalBalance: round4(goalAmount)
1725
+ };
1726
+ }
1651
1727
 
1652
1728
  exports.BASE_LABELS = BASE_LABELS;
1653
1729
  exports.BASE_PREFIXES = BASE_PREFIXES;
@@ -1673,6 +1749,7 @@ exports.calculateLoan = calculateLoan;
1673
1749
  exports.calculateMarginMarkup = calculateMarginMarkup;
1674
1750
  exports.calculatePercentageChange = calculatePercentageChange;
1675
1751
  exports.calculateRuleOf72 = calculateRuleOf72;
1752
+ exports.calculateSavingsGoal = calculateSavingsGoal;
1676
1753
  exports.calculateSimpleInterest = calculateSimpleInterest;
1677
1754
  exports.calculateTax = calculateTax;
1678
1755
  exports.calculateTimeValue = calculateTimeValue;
@@ -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, 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
+ 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 SavingsGoalInput, _ as SavingsGoalMode, $ as SavingsGoalResult, a0 as SemverVersion, a1 as SimpleInterestResult, a2 as SubnetInfo, a3 as SuccessiveDiscountResult, a4 as SuccessiveDiscountStep, a5 as TaxDirection, a6 as TaxResult, a7 as TimeValueDirection, a8 as TimeValueResult, a9 as TipSplitResult, aa as VideoBitrateInput, ab as VideoBitrateMode, ac as VideoBitrateResult, ad as ViewportConvertResult, ae as applySuccessiveDiscounts, af as autoFormat, ag as bumpVersion, ah as calcAspectRatio, ai as calcSubnet, aj as calculateBreakEven, ak as calculateCompoundInterest, al as calculateDiscount, am as calculateEmi, an as calculateLoan, ao as calculateMarginMarkup, ap as calculatePercentageChange, aq as calculateRuleOf72, ar as calculateSavingsGoal, as as calculateSimpleInterest, at as calculateTax, au as calculateTimeValue, av as calculateTipSplit, aw as calculateVideoBitrate, ax as compareSemver, ay as convert, az as convertAprApy, aA as convertBytes, aB as convertIp, aC as coverBox, aD as decimalToIp, aE as decimalToIpCidr, aF as describePermissions, aG as fitIntoBox, aH as formatNumber, aI as formatValue, aJ as formatVwValue, aK as formatWithSeparator, aL as gcd, aM as ipFromBinary, aN as ipFromDecimal, aO as ipFromHex, aP as ipToBinary, aQ as ipToDecimal, aR as ipToDecimalCidr, aS as ipToHex, aT as ipToOctal, aU as isValid, aV as isValidCidr, aW as isValidIp, aX as isValidIpv4, aY as marginToMarkup, aZ as markupToMargin, a_ as octalToPermissions, a$ as parseFileSize, b0 as parseInput, b1 as parseNumberString, b2 as parseSemver, b3 as permissionsToChmod, b4 as permissionsToOctal, b5 as permissionsToSymbolic, b6 as ptToPx, b7 as pxToAll, b8 as pxToViewport, b9 as remToPx, ba as satisfiesRange, bb as scaleByHeight, bc as scaleByWidth, bd as sortVersions, be as splitSubnet, bf as symbolicToPermissions, bg as validateBarcode, bh as validateCardNumber, bi as validateIban, bj as validateIsbn, bk as viewportToPx } from '../units-BhoxdHhs.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, 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
+ 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 SavingsGoalInput, _ as SavingsGoalMode, $ as SavingsGoalResult, a0 as SemverVersion, a1 as SimpleInterestResult, a2 as SubnetInfo, a3 as SuccessiveDiscountResult, a4 as SuccessiveDiscountStep, a5 as TaxDirection, a6 as TaxResult, a7 as TimeValueDirection, a8 as TimeValueResult, a9 as TipSplitResult, aa as VideoBitrateInput, ab as VideoBitrateMode, ac as VideoBitrateResult, ad as ViewportConvertResult, ae as applySuccessiveDiscounts, af as autoFormat, ag as bumpVersion, ah as calcAspectRatio, ai as calcSubnet, aj as calculateBreakEven, ak as calculateCompoundInterest, al as calculateDiscount, am as calculateEmi, an as calculateLoan, ao as calculateMarginMarkup, ap as calculatePercentageChange, aq as calculateRuleOf72, ar as calculateSavingsGoal, as as calculateSimpleInterest, at as calculateTax, au as calculateTimeValue, av as calculateTipSplit, aw as calculateVideoBitrate, ax as compareSemver, ay as convert, az as convertAprApy, aA as convertBytes, aB as convertIp, aC as coverBox, aD as decimalToIp, aE as decimalToIpCidr, aF as describePermissions, aG as fitIntoBox, aH as formatNumber, aI as formatValue, aJ as formatVwValue, aK as formatWithSeparator, aL as gcd, aM as ipFromBinary, aN as ipFromDecimal, aO as ipFromHex, aP as ipToBinary, aQ as ipToDecimal, aR as ipToDecimalCidr, aS as ipToHex, aT as ipToOctal, aU as isValid, aV as isValidCidr, aW as isValidIp, aX as isValidIpv4, aY as marginToMarkup, aZ as markupToMargin, a_ as octalToPermissions, a$ as parseFileSize, b0 as parseInput, b1 as parseNumberString, b2 as parseSemver, b3 as permissionsToChmod, b4 as permissionsToOctal, b5 as permissionsToSymbolic, b6 as ptToPx, b7 as pxToAll, b8 as pxToViewport, b9 as remToPx, ba as satisfiesRange, bb as scaleByHeight, bc as scaleByWidth, bd as sortVersions, be as splitSubnet, bf as symbolicToPermissions, bg as validateBarcode, bh as validateCardNumber, bi as validateIban, bj as validateIsbn, bk as viewportToPx } from '../units-BhoxdHhs.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, 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';
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, calculateSavingsGoal, 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-ZPQOE7KD.js';
2
2
  import '../chunk-MLKGABMK.js';