@utilix-tech/sdk 0.44.0 → 0.46.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 +8 -0
- package/README.md +26 -6
- package/dist/{chunk-GZBSKZ6F.js → chunk-7PEKYLRB.js} +104 -1
- package/dist/{chunk-WT3Q5LCN.js → chunk-KMQHBUYO.js} +94 -1
- package/dist/{chunk-F2CEN226.js → chunk-P7TXG7CI.js} +127 -1
- package/dist/index.cjs +322 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{network-BlOVDE3Y.d.ts → network-Bzm1tjMA.d.cts} +60 -2
- package/dist/{network-BlOVDE3Y.d.cts → network-Bzm1tjMA.d.ts} +60 -2
- package/dist/{text-kHkT9VtT.d.cts → text-DWUcY8H1.d.cts} +34 -2
- package/dist/{text-kHkT9VtT.d.ts → text-DWUcY8H1.d.ts} +34 -2
- package/dist/tools/network.cjs +103 -0
- package/dist/tools/network.d.cts +1 -1
- package/dist/tools/network.d.ts +1 -1
- package/dist/tools/network.js +1 -1
- package/dist/tools/text.cjs +126 -0
- package/dist/tools/text.d.cts +1 -1
- package/dist/tools/text.d.ts +1 -1
- package/dist/tools/text.js +1 -1
- package/dist/tools/units.cjs +93 -0
- package/dist/tools/units.d.cts +1 -1
- package/dist/tools/units.d.ts +1 -1
- package/dist/tools/units.js +1 -1
- package/dist/{units-WAgBQ7D7.d.cts → units-DU4Pisfx.d.cts} +63 -2
- package/dist/{units-WAgBQ7D7.d.ts → units-DU4Pisfx.d.ts} +63 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.46.0
|
|
6
|
+
- Add `calculateDepreciationSchedule` (depreciation-schedule-calculator): build a year-by-year fixed-asset depreciation schedule from cost, salvage value, and useful life, using straight-line, double-declining-balance, or sum-of-years-digits.
|
|
7
|
+
- Add `analyzeKeywordDensity` (keyword-density-analyzer): count keyword/phrase frequency and density (occurrences per 100 words) across a block of text, with single-word or 2/3-word phrase modes.
|
|
8
|
+
|
|
9
|
+
## 0.45.0
|
|
10
|
+
- Add `calculateCdMaturity` (cd-maturity-calculator): compute a certificate of deposit's maturity value and effective annual yield (APY) from a principal, nominal rate, term, and compounding frequency, plus the net payout if withdrawn early.
|
|
11
|
+
- Add `buildClientHints`, `parseClientHintHeaders` (client-hints-header-builder): build an `Accept-CH`/`Critical-CH` response header from a list of client hint names with a plain-English note per hint, or decode raw Client Hints request-header text into structured values.
|
|
12
|
+
|
|
5
13
|
## 0.44.0
|
|
6
14
|
- Add `buildPermissionsPolicy`, `parsePermissionsPolicy` (permissions-policy-builder): build a `Permissions-Policy` response header from browser features and their per-feature allowlist with a plain-English note per feature, or parse an existing one into the same shape.
|
|
7
15
|
- Add `calculatePaybackPeriod` (payback-period-calculator): compute the simple and discounted payback period from an initial investment and a series of periodic cash flows.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**632 developer utility functions for Node.js: runs locally, no API key required.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
6
6
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
@@ -149,7 +149,7 @@ generateEtag("console.log(1)");
|
|
|
149
149
|
import { convertCase, slugify, countWords, generateWords, generateParagraphs,
|
|
150
150
|
escapeString, htmlToMarkdown, applyOps, detectPassiveVoice, scoreReadability,
|
|
151
151
|
detectFillerWords, calculateStringDistance, analyzeSentenceLengths,
|
|
152
|
-
searchEmoji, getEmojiByShortcode } from "@utilix-tech/sdk/text";
|
|
152
|
+
analyzeKeywordDensity, searchEmoji, getEmojiByShortcode } from "@utilix-tech/sdk/text";
|
|
153
153
|
|
|
154
154
|
convertCase("hello world", "camelCase"); // "helloWorld"
|
|
155
155
|
convertCase("hello world", "PascalCase"); // "HelloWorld"
|
|
@@ -190,6 +190,10 @@ analyzeSentenceLengths("The cat sat on the mat. It was a sunny day, and the dog
|
|
|
190
190
|
// Search ~280 common emoji by name, keyword, or GitHub-style shortcode
|
|
191
191
|
searchEmoji("fire"); // [{ emoji: "🔥", name: "fire", shortcode: "fire", codepoint: "U+1F525", ... }]
|
|
192
192
|
getEmojiByShortcode(":joy:"); // { emoji: "😂", name: "face with tears of joy", ... }
|
|
193
|
+
|
|
194
|
+
// Keyword/phrase frequency and density (occurrences per 100 words); ngramSize 2 or 3 for phrases
|
|
195
|
+
analyzeKeywordDensity("machine learning models power machine learning systems");
|
|
196
|
+
// { totalWords: 7, uniqueKeywords: 5, ngramSize: 1, keywords: [{ keyword: "learning", count: 2, density: 28.6 }, ...] }
|
|
193
197
|
```
|
|
194
198
|
|
|
195
199
|
---
|
|
@@ -312,7 +316,7 @@ formatIso8601Duration(90061); // { iso: "P1DT1H1M1S", ... }
|
|
|
312
316
|
### `/units`: Conversions
|
|
313
317
|
|
|
314
318
|
```ts
|
|
315
|
-
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72, calculateEmi, calculateRoi, compareUnitPrices, calculatePaybackPeriod } from "@utilix-tech/sdk/units";
|
|
319
|
+
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72, calculateEmi, calculateRoi, compareUnitPrices, calculatePaybackPeriod, calculateCdMaturity, calculateDepreciationSchedule } from "@utilix-tech/sdk/units";
|
|
316
320
|
|
|
317
321
|
// File sizes
|
|
318
322
|
convertBytes(1073741824, "GB"); // 1
|
|
@@ -426,6 +430,14 @@ calculateChange(4.65, 5.0, USD_DENOMINATIONS);
|
|
|
426
430
|
// Payback period: simple + discounted, from an initial investment and periodic cash flows
|
|
427
431
|
calculatePaybackPeriod({ initialInvestment: 1000, cashFlows: [400, 400, 400], discountRatePercent: 8 });
|
|
428
432
|
// { paybackPeriod: 2.5, paybackPeriodRounded: 3, recovered: true, discountedPaybackPeriod: 2.9029, ... }
|
|
433
|
+
|
|
434
|
+
// Certificate of deposit maturity value, APY, and net early-withdrawal payout
|
|
435
|
+
calculateCdMaturity(1000, 12, 12, 12, 3);
|
|
436
|
+
// { maturityValue: 1126.83, totalInterest: 126.83, apy: 12.6825, earlyWithdrawalPayout: 1096.83, ... }
|
|
437
|
+
|
|
438
|
+
// Year-by-year depreciation schedule: straight-line, double-declining-balance, or sum-of-years-digits
|
|
439
|
+
calculateDepreciationSchedule(10000, 1000, 5, "straight-line");
|
|
440
|
+
// { totalDepreciation: 9000, schedule: [{ year: 1, depreciationExpense: 1800, accumulatedDepreciation: 1800, bookValue: 8200 }, ...] }
|
|
429
441
|
```
|
|
430
442
|
|
|
431
443
|
---
|
|
@@ -438,7 +450,7 @@ import { getStatusCode, isValidIp, isValidIpv4, isValidIpv6,
|
|
|
438
450
|
parseHar, validateSitemap, validateRobotsTxt,
|
|
439
451
|
parseUserAgent, buildCacheControl, buildReferrerPolicy, parseIpv6Address, buildLinkHeader, checkSetCookieHeader, analyzeEmailHeaders,
|
|
440
452
|
buildRangeHeader, parseContentRangeHeader, buildVaryHeader, parseVaryHeader, validateManifest,
|
|
441
|
-
buildPermissionsPolicy, parsePermissionsPolicy } from "@utilix-tech/sdk/network";
|
|
453
|
+
buildPermissionsPolicy, parsePermissionsPolicy, buildClientHints, parseClientHintHeaders } from "@utilix-tech/sdk/network";
|
|
442
454
|
|
|
443
455
|
getStatusCode(404);
|
|
444
456
|
// { code: 404, text: "Not Found", description: "...", category: "Client Error" }
|
|
@@ -521,6 +533,14 @@ buildPermissionsPolicy([{ feature: "camera", allowlist: [] }, { feature: "geoloc
|
|
|
521
533
|
// Parse an existing Permissions-Policy header value into the same shape
|
|
522
534
|
parsePermissionsPolicy("camera=(), geolocation=(self)");
|
|
523
535
|
// { header: "Permissions-Policy: camera=(), geolocation=(self)", directives: [...], warnings: [] }
|
|
536
|
+
|
|
537
|
+
// Build an Accept-CH header from a list of client hint names, with a plain-English note per hint
|
|
538
|
+
buildClientHints(["Sec-CH-UA-Platform", "Sec-CH-DPR"]);
|
|
539
|
+
// { acceptCH: "Sec-CH-UA-Platform, Sec-CH-DPR", hints: [...] }
|
|
540
|
+
|
|
541
|
+
// Decode raw Client Hints request-header text into structured values
|
|
542
|
+
parseClientHintHeaders("Sec-CH-UA-Mobile: ?0");
|
|
543
|
+
// { hints: [{ name: "Sec-CH-UA-Mobile", value: false, ... }], unrecognized: [] }
|
|
524
544
|
```
|
|
525
545
|
|
|
526
546
|
---
|
|
@@ -758,8 +778,8 @@ readVideoInfo(new Uint8Array(videoBytes));
|
|
|
758
778
|
| `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, SRT/WebVTT subtitles, Markdown front matter parser |
|
|
759
779
|
| `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, entropy estimator, fake data |
|
|
760
780
|
| `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
|
|
761
|
-
| `@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, savings goal calculator, ROI calculator, cash denomination/till calculator, payback period calculator |
|
|
762
|
-
| `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing, User-Agent parsing, IPv6 address compress/expand, Permissions-Policy header builder |
|
|
781
|
+
| `@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, savings goal calculator, ROI calculator, cash denomination/till calculator, payback period calculator, CD maturity calculator |
|
|
782
|
+
| `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing, User-Agent parsing, IPv6 address compress/expand, Permissions-Policy header builder, Client Hints header builder/parser |
|
|
763
783
|
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
|
|
764
784
|
| `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format, MIME type lookup, GitHub URL parsing, regex ReDoS detector, Conventional Commits linter |
|
|
765
785
|
| `@utilix-tech/sdk/color` | Hex/RGB/HSL/HSV/CMYK convert, palette generation, contrast check |
|
|
@@ -3,6 +3,7 @@ import { __export } from './chunk-MLKGABMK.js';
|
|
|
3
3
|
// src/tools/network.ts
|
|
4
4
|
var network_exports = {};
|
|
5
5
|
__export(network_exports, {
|
|
6
|
+
CLIENT_HINTS: () => CLIENT_HINTS,
|
|
6
7
|
DNS_RECORD_TYPES: () => DNS_RECORD_TYPES,
|
|
7
8
|
HTTP_HEADERS: () => HTTP_HEADERS,
|
|
8
9
|
LINK_REL_VALUES: () => LINK_REL_VALUES,
|
|
@@ -11,6 +12,7 @@ __export(network_exports, {
|
|
|
11
12
|
STATUS_CODES: () => STATUS_CODES,
|
|
12
13
|
analyzeEmailHeaders: () => analyzeEmailHeaders,
|
|
13
14
|
buildCacheControl: () => buildCacheControl,
|
|
15
|
+
buildClientHints: () => buildClientHints,
|
|
14
16
|
buildDnsQueryUrl: () => buildDnsQueryUrl,
|
|
15
17
|
buildGeoUrl: () => buildGeoUrl,
|
|
16
18
|
buildLinkHeader: () => buildLinkHeader,
|
|
@@ -34,6 +36,7 @@ __export(network_exports, {
|
|
|
34
36
|
isValidIp: () => isValidIp,
|
|
35
37
|
isValidIpv4: () => isValidIpv4,
|
|
36
38
|
isValidIpv6: () => isValidIpv6,
|
|
39
|
+
parseClientHintHeaders: () => parseClientHintHeaders,
|
|
37
40
|
parseContentRangeHeader: () => parseContentRangeHeader,
|
|
38
41
|
parseDnsResponse: () => parseDnsResponse,
|
|
39
42
|
parseGeoResponse: () => parseGeoResponse,
|
|
@@ -2575,5 +2578,105 @@ function parsePermissionsPolicy(raw) {
|
|
|
2575
2578
|
if (features.length === 0) return { error: "No directives found" };
|
|
2576
2579
|
return buildPermissionsPolicy(features);
|
|
2577
2580
|
}
|
|
2581
|
+
var CLIENT_HINTS = [
|
|
2582
|
+
{ name: "Sec-CH-UA", description: "The browser's brand(s) and significant version, sent automatically on every request without an Accept-CH opt-in.", lowEntropy: true, valueType: "sf-list-brand" },
|
|
2583
|
+
{ name: "Sec-CH-UA-Mobile", description: "Whether the browser is running on a mobile device (?1) or not (?0).", lowEntropy: true, valueType: "boolean" },
|
|
2584
|
+
{ name: "Sec-CH-UA-Platform", description: 'The platform/OS the browser is running on, e.g. "Windows" or "Android".', lowEntropy: true, valueType: "string" },
|
|
2585
|
+
{ name: "Sec-CH-UA-Full-Version-List", description: "The full version number for each brand in the user agent, not just the significant version.", lowEntropy: false, valueType: "sf-list-brand" },
|
|
2586
|
+
{ name: "Sec-CH-UA-Platform-Version", description: 'The exact OS version, e.g. "15.0.0".', lowEntropy: false, valueType: "string" },
|
|
2587
|
+
{ name: "Sec-CH-UA-Arch", description: 'The underlying CPU architecture, e.g. "x86" or "arm".', lowEntropy: false, valueType: "string" },
|
|
2588
|
+
{ name: "Sec-CH-UA-Bitness", description: 'The CPU architecture bitness, e.g. "64".', lowEntropy: false, valueType: "string" },
|
|
2589
|
+
{ name: "Sec-CH-UA-Model", description: "The device model, mostly populated on mobile devices.", lowEntropy: false, valueType: "string" },
|
|
2590
|
+
{ name: "Sec-CH-UA-WoW64", description: "Whether a 32-bit browser is running on 64-bit Windows.", lowEntropy: false, valueType: "boolean" },
|
|
2591
|
+
{ name: "Sec-CH-UA-Form-Factor", description: `The device's form factor, e.g. "Desktop", "Mobile", "Tablet", or "XR".`, lowEntropy: false, valueType: "string" },
|
|
2592
|
+
{ name: "Sec-CH-Prefers-Color-Scheme", description: "The user's preferred color scheme, mirrors the prefers-color-scheme media feature.", lowEntropy: false, valueType: "string" },
|
|
2593
|
+
{ name: "Sec-CH-Prefers-Reduced-Motion", description: "Whether the user has requested reduced motion.", lowEntropy: false, valueType: "string" },
|
|
2594
|
+
{ name: "Sec-CH-Prefers-Reduced-Transparency", description: "Whether the user has requested reduced transparency.", lowEntropy: false, valueType: "string" },
|
|
2595
|
+
{ name: "Sec-CH-Viewport-Width", description: "The layout viewport width in CSS pixels.", lowEntropy: false, valueType: "number" },
|
|
2596
|
+
{ name: "Sec-CH-Viewport-Height", description: "The layout viewport height in CSS pixels.", lowEntropy: false, valueType: "number" },
|
|
2597
|
+
{ name: "Sec-CH-DPR", description: "The device pixel ratio.", lowEntropy: false, valueType: "number" },
|
|
2598
|
+
{ name: "Sec-CH-Width", description: "The intrinsic width of a requested image resource, set per-request via the image's `sizes` attribute.", lowEntropy: false, valueType: "number" },
|
|
2599
|
+
{ name: "Sec-CH-Device-Memory", description: "Approximate device RAM in GiB, rounded to the nearest power of two for privacy.", lowEntropy: false, valueType: "number" },
|
|
2600
|
+
{ name: "Save-Data", description: "Legacy hint signaling the user opted into a reduced-data mode; sent automatically like a low-entropy hint.", lowEntropy: true, valueType: "boolean" }
|
|
2601
|
+
];
|
|
2602
|
+
function _findClientHint(raw) {
|
|
2603
|
+
const normalized = raw.trim().toLowerCase();
|
|
2604
|
+
return CLIENT_HINTS.find((d) => d.name.toLowerCase() === normalized);
|
|
2605
|
+
}
|
|
2606
|
+
function buildClientHints(hintNames, criticalHintNames = []) {
|
|
2607
|
+
if (!Array.isArray(hintNames) || hintNames.length === 0) return { error: "At least one client hint is required" };
|
|
2608
|
+
const resolved = [];
|
|
2609
|
+
for (const raw of hintNames) {
|
|
2610
|
+
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
2611
|
+
const def = _findClientHint(raw);
|
|
2612
|
+
if (!def) return { error: `Unknown client hint: "${raw}"` };
|
|
2613
|
+
resolved.push(def);
|
|
2614
|
+
}
|
|
2615
|
+
if (resolved.length === 0) return { error: "At least one client hint is required" };
|
|
2616
|
+
const critical = [];
|
|
2617
|
+
if (Array.isArray(criticalHintNames)) {
|
|
2618
|
+
for (const raw of criticalHintNames) {
|
|
2619
|
+
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
2620
|
+
const def = _findClientHint(raw);
|
|
2621
|
+
if (!def) return { error: `Unknown client hint: "${raw}"` };
|
|
2622
|
+
if (!resolved.some((d) => d.name === def.name)) {
|
|
2623
|
+
return { error: `Critical hint "${def.name}" must also be included in hintNames` };
|
|
2624
|
+
}
|
|
2625
|
+
critical.push(def);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
const uniqueNames = Array.from(new Set(resolved.map((d) => d.name)));
|
|
2629
|
+
const result = {
|
|
2630
|
+
acceptCH: uniqueNames.join(", "),
|
|
2631
|
+
hints: resolved.map((d) => ({ name: d.name, description: d.description, lowEntropy: d.lowEntropy }))
|
|
2632
|
+
};
|
|
2633
|
+
if (critical.length > 0) {
|
|
2634
|
+
result.criticalCH = Array.from(new Set(critical.map((d) => d.name))).join(", ");
|
|
2635
|
+
}
|
|
2636
|
+
return result;
|
|
2637
|
+
}
|
|
2638
|
+
function _decodeClientHintValue(valueType, rawValue) {
|
|
2639
|
+
switch (valueType) {
|
|
2640
|
+
case "boolean":
|
|
2641
|
+
if (rawValue === "?1") return true;
|
|
2642
|
+
if (rawValue === "?0") return false;
|
|
2643
|
+
return rawValue;
|
|
2644
|
+
case "string":
|
|
2645
|
+
return rawValue.replace(/^"|"$/g, "");
|
|
2646
|
+
case "number": {
|
|
2647
|
+
const n = Number(rawValue);
|
|
2648
|
+
return Number.isFinite(n) ? n : rawValue;
|
|
2649
|
+
}
|
|
2650
|
+
case "sf-list-brand":
|
|
2651
|
+
return rawValue.split(",").map((part) => {
|
|
2652
|
+
const m = part.trim().match(/^"([^"]*)";v="([^"]*)"$/);
|
|
2653
|
+
return m ? { brand: m[1], version: m[2] } : { raw: part.trim() };
|
|
2654
|
+
});
|
|
2655
|
+
default:
|
|
2656
|
+
return rawValue;
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
function parseClientHintHeaders(rawHeaders) {
|
|
2660
|
+
if (typeof rawHeaders !== "string" || rawHeaders.trim() === "") return { error: "Provide one or more header lines to parse" };
|
|
2661
|
+
const lines = rawHeaders.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
2662
|
+
const hints = [];
|
|
2663
|
+
const unrecognized = [];
|
|
2664
|
+
for (const line of lines) {
|
|
2665
|
+
const idx = line.indexOf(":");
|
|
2666
|
+
if (idx === -1) continue;
|
|
2667
|
+
const name = line.slice(0, idx).trim();
|
|
2668
|
+
const rawValue = line.slice(idx + 1).trim();
|
|
2669
|
+
const def = _findClientHint(name);
|
|
2670
|
+
if (!def) {
|
|
2671
|
+
unrecognized.push({ name, rawValue });
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
hints.push({ name: def.name, rawValue, description: def.description, value: _decodeClientHintValue(def.valueType, rawValue) });
|
|
2675
|
+
}
|
|
2676
|
+
if (hints.length === 0 && unrecognized.length === 0) {
|
|
2677
|
+
return { error: 'No parsable header lines found (expected "Header-Name: value" per line)' };
|
|
2678
|
+
}
|
|
2679
|
+
return { hints, unrecognized };
|
|
2680
|
+
}
|
|
2578
2681
|
|
|
2579
|
-
export { DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, PERMISSIONS_POLICY_FEATURES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildPermissionsPolicy, buildRangeHeader, buildReferrerPolicy, buildVaryHeader, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parsePermissionsPolicy, parseUserAgent, parseVaryHeader, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateManifest, validateRobotsTxt, validateSitemap };
|
|
2682
|
+
export { CLIENT_HINTS, DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, PERMISSIONS_POLICY_FEATURES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildClientHints, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildPermissionsPolicy, buildRangeHeader, buildReferrerPolicy, buildVaryHeader, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseClientHintHeaders, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parsePermissionsPolicy, parseUserAgent, parseVaryHeader, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateManifest, validateRobotsTxt, validateSitemap };
|
|
@@ -22,8 +22,10 @@ __export(units_exports, {
|
|
|
22
22
|
calcSubnet: () => calcSubnet,
|
|
23
23
|
calculateBreakEven: () => calculateBreakEven,
|
|
24
24
|
calculateCashBreakdown: () => calculateCashBreakdown,
|
|
25
|
+
calculateCdMaturity: () => calculateCdMaturity,
|
|
25
26
|
calculateChange: () => calculateChange,
|
|
26
27
|
calculateCompoundInterest: () => calculateCompoundInterest,
|
|
28
|
+
calculateDepreciationSchedule: () => calculateDepreciationSchedule,
|
|
27
29
|
calculateDiscount: () => calculateDiscount,
|
|
28
30
|
calculateEmi: () => calculateEmi,
|
|
29
31
|
calculateLoan: () => calculateLoan,
|
|
@@ -1983,5 +1985,96 @@ function calculatePaybackPeriod(input) {
|
|
|
1983
1985
|
}
|
|
1984
1986
|
return result;
|
|
1985
1987
|
}
|
|
1988
|
+
function calculateCdMaturity(principal, annualRatePercent, termMonths, compoundsPerYear, earlyWithdrawalPenaltyMonths) {
|
|
1989
|
+
if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a finite number greater than zero" };
|
|
1990
|
+
if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
|
|
1991
|
+
return { error: "Annual interest rate must be zero or a positive number" };
|
|
1992
|
+
}
|
|
1993
|
+
if (!Number.isFinite(termMonths) || termMonths <= 0) return { error: "Term must be a positive number of months" };
|
|
1994
|
+
if (!Number.isInteger(compoundsPerYear) || compoundsPerYear <= 0) {
|
|
1995
|
+
return { error: "Compounding frequency must be a positive whole number of periods per year" };
|
|
1996
|
+
}
|
|
1997
|
+
if (earlyWithdrawalPenaltyMonths !== void 0 && (!Number.isFinite(earlyWithdrawalPenaltyMonths) || earlyWithdrawalPenaltyMonths < 0)) {
|
|
1998
|
+
return { error: "earlyWithdrawalPenaltyMonths must be zero or a positive number when provided" };
|
|
1999
|
+
}
|
|
2000
|
+
const round22 = (n) => Math.round(n * 100) / 100;
|
|
2001
|
+
const round4 = (n) => Math.round(n * 1e4) / 1e4;
|
|
2002
|
+
const ratePerPeriod = annualRatePercent / 100 / compoundsPerYear;
|
|
2003
|
+
const totalPeriods = compoundsPerYear * (termMonths / 12);
|
|
2004
|
+
const growth = ratePerPeriod === 0 ? 1 : Math.pow(1 + ratePerPeriod, totalPeriods);
|
|
2005
|
+
const maturityValue = principal * growth;
|
|
2006
|
+
const totalInterest = maturityValue - principal;
|
|
2007
|
+
const apy = ratePerPeriod === 0 ? 0 : (Math.pow(1 + ratePerPeriod, compoundsPerYear) - 1) * 100;
|
|
2008
|
+
const result = {
|
|
2009
|
+
principal: round22(principal),
|
|
2010
|
+
annualRatePercent: round4(annualRatePercent),
|
|
2011
|
+
termMonths,
|
|
2012
|
+
compoundsPerYear,
|
|
2013
|
+
maturityValue: round22(maturityValue),
|
|
2014
|
+
totalInterest: round22(totalInterest),
|
|
2015
|
+
apy: round4(apy)
|
|
2016
|
+
};
|
|
2017
|
+
if (earlyWithdrawalPenaltyMonths !== void 0) {
|
|
2018
|
+
const monthlyRate = annualRatePercent / 100 / 12;
|
|
2019
|
+
const forfeited = Math.min(principal * monthlyRate * earlyWithdrawalPenaltyMonths, Math.max(totalInterest, 0));
|
|
2020
|
+
result.earlyWithdrawalPenaltyMonths = earlyWithdrawalPenaltyMonths;
|
|
2021
|
+
result.earlyWithdrawalForfeitedInterest = round22(forfeited);
|
|
2022
|
+
result.earlyWithdrawalPayout = round22(maturityValue - forfeited);
|
|
2023
|
+
}
|
|
2024
|
+
return result;
|
|
2025
|
+
}
|
|
2026
|
+
var DEPRECIATION_METHODS = ["straight-line", "double-declining-balance", "sum-of-years-digits"];
|
|
2027
|
+
function calculateDepreciationSchedule(cost, salvageValue, usefulLifeYears, method) {
|
|
2028
|
+
if (!Number.isFinite(cost) || cost <= 0) return { error: "Cost must be a positive number" };
|
|
2029
|
+
if (!Number.isFinite(salvageValue) || salvageValue < 0) {
|
|
2030
|
+
return { error: "Salvage value must be zero or a positive number" };
|
|
2031
|
+
}
|
|
2032
|
+
if (salvageValue >= cost) return { error: "Salvage value must be less than cost" };
|
|
2033
|
+
if (!Number.isInteger(usefulLifeYears) || usefulLifeYears <= 0) {
|
|
2034
|
+
return { error: "Useful life must be a positive whole number of years" };
|
|
2035
|
+
}
|
|
2036
|
+
if (!DEPRECIATION_METHODS.includes(method)) {
|
|
2037
|
+
return { error: `Method must be one of: ${DEPRECIATION_METHODS.join(", ")}` };
|
|
2038
|
+
}
|
|
2039
|
+
const round22 = (n) => Math.round(n * 100) / 100;
|
|
2040
|
+
const depreciableBase = round22(cost - salvageValue);
|
|
2041
|
+
const schedule = [];
|
|
2042
|
+
let accumulated = 0;
|
|
2043
|
+
if (method === "straight-line") {
|
|
2044
|
+
const annual = round22(depreciableBase / usefulLifeYears);
|
|
2045
|
+
for (let year = 1; year <= usefulLifeYears; year++) {
|
|
2046
|
+
const expense = year === usefulLifeYears ? round22(depreciableBase - accumulated) : annual;
|
|
2047
|
+
accumulated = round22(accumulated + expense);
|
|
2048
|
+
schedule.push({ year, depreciationExpense: expense, accumulatedDepreciation: accumulated, bookValue: round22(cost - accumulated) });
|
|
2049
|
+
}
|
|
2050
|
+
} else if (method === "double-declining-balance") {
|
|
2051
|
+
const rate = 2 / usefulLifeYears;
|
|
2052
|
+
let bookValue = cost;
|
|
2053
|
+
for (let year = 1; year <= usefulLifeYears; year++) {
|
|
2054
|
+
let expense = round22(bookValue * rate);
|
|
2055
|
+
if (bookValue - expense < salvageValue) expense = round22(bookValue - salvageValue);
|
|
2056
|
+
if (expense < 0) expense = 0;
|
|
2057
|
+
bookValue = round22(bookValue - expense);
|
|
2058
|
+
accumulated = round22(accumulated + expense);
|
|
2059
|
+
schedule.push({ year, depreciationExpense: expense, accumulatedDepreciation: accumulated, bookValue });
|
|
2060
|
+
}
|
|
2061
|
+
} else {
|
|
2062
|
+
const sumOfYears = usefulLifeYears * (usefulLifeYears + 1) / 2;
|
|
2063
|
+
for (let year = 1; year <= usefulLifeYears; year++) {
|
|
2064
|
+
const fraction = (usefulLifeYears - year + 1) / sumOfYears;
|
|
2065
|
+
const expense = year === usefulLifeYears ? round22(depreciableBase - accumulated) : round22(fraction * depreciableBase);
|
|
2066
|
+
accumulated = round22(accumulated + expense);
|
|
2067
|
+
schedule.push({ year, depreciationExpense: expense, accumulatedDepreciation: accumulated, bookValue: round22(cost - accumulated) });
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return {
|
|
2071
|
+
cost,
|
|
2072
|
+
salvageValue,
|
|
2073
|
+
usefulLifeYears,
|
|
2074
|
+
method,
|
|
2075
|
+
totalDepreciation: accumulated,
|
|
2076
|
+
schedule
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
1986
2079
|
|
|
1987
|
-
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, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCashBreakdown, calculateChange, calculateCompoundInterest, calculateDiscount, calculateEmi, calculateLoan, calculateMarginMarkup, calculatePaybackPeriod, calculatePercentageChange, calculateRoi, calculateRuleOf72, calculateSavingsGoal, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, compareUnitPrices, 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 };
|
|
2080
|
+
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, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCashBreakdown, calculateCdMaturity, calculateChange, calculateCompoundInterest, calculateDepreciationSchedule, calculateDiscount, calculateEmi, calculateLoan, calculateMarginMarkup, calculatePaybackPeriod, calculatePercentageChange, calculateRoi, calculateRuleOf72, calculateSavingsGoal, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, compareUnitPrices, 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 };
|
|
@@ -11,6 +11,7 @@ __export(text_exports, {
|
|
|
11
11
|
LINE_OPS: () => LINE_OPS,
|
|
12
12
|
MORSE_CODE: () => MORSE_CODE,
|
|
13
13
|
addBorder: () => addBorder,
|
|
14
|
+
analyzeKeywordDensity: () => analyzeKeywordDensity,
|
|
14
15
|
analyzeSentenceLengths: () => analyzeSentenceLengths,
|
|
15
16
|
analyzeText: () => analyzeText,
|
|
16
17
|
applyOp: () => applyOp,
|
|
@@ -2670,6 +2671,131 @@ function analyzeSentenceLengths(text) {
|
|
|
2670
2671
|
buckets
|
|
2671
2672
|
};
|
|
2672
2673
|
}
|
|
2674
|
+
var KEYWORD_DENSITY_STOPWORDS = /* @__PURE__ */ new Set([
|
|
2675
|
+
"a",
|
|
2676
|
+
"an",
|
|
2677
|
+
"the",
|
|
2678
|
+
"and",
|
|
2679
|
+
"or",
|
|
2680
|
+
"but",
|
|
2681
|
+
"if",
|
|
2682
|
+
"then",
|
|
2683
|
+
"else",
|
|
2684
|
+
"for",
|
|
2685
|
+
"nor",
|
|
2686
|
+
"so",
|
|
2687
|
+
"yet",
|
|
2688
|
+
"of",
|
|
2689
|
+
"in",
|
|
2690
|
+
"on",
|
|
2691
|
+
"at",
|
|
2692
|
+
"to",
|
|
2693
|
+
"from",
|
|
2694
|
+
"by",
|
|
2695
|
+
"with",
|
|
2696
|
+
"about",
|
|
2697
|
+
"against",
|
|
2698
|
+
"between",
|
|
2699
|
+
"into",
|
|
2700
|
+
"through",
|
|
2701
|
+
"during",
|
|
2702
|
+
"before",
|
|
2703
|
+
"after",
|
|
2704
|
+
"above",
|
|
2705
|
+
"below",
|
|
2706
|
+
"up",
|
|
2707
|
+
"down",
|
|
2708
|
+
"out",
|
|
2709
|
+
"off",
|
|
2710
|
+
"over",
|
|
2711
|
+
"under",
|
|
2712
|
+
"again",
|
|
2713
|
+
"further",
|
|
2714
|
+
"once",
|
|
2715
|
+
"is",
|
|
2716
|
+
"are",
|
|
2717
|
+
"was",
|
|
2718
|
+
"were",
|
|
2719
|
+
"be",
|
|
2720
|
+
"been",
|
|
2721
|
+
"being",
|
|
2722
|
+
"am",
|
|
2723
|
+
"do",
|
|
2724
|
+
"does",
|
|
2725
|
+
"did",
|
|
2726
|
+
"doing",
|
|
2727
|
+
"have",
|
|
2728
|
+
"has",
|
|
2729
|
+
"had",
|
|
2730
|
+
"having",
|
|
2731
|
+
"i",
|
|
2732
|
+
"me",
|
|
2733
|
+
"my",
|
|
2734
|
+
"we",
|
|
2735
|
+
"our",
|
|
2736
|
+
"you",
|
|
2737
|
+
"your",
|
|
2738
|
+
"he",
|
|
2739
|
+
"him",
|
|
2740
|
+
"his",
|
|
2741
|
+
"she",
|
|
2742
|
+
"her",
|
|
2743
|
+
"it",
|
|
2744
|
+
"its",
|
|
2745
|
+
"they",
|
|
2746
|
+
"them",
|
|
2747
|
+
"their",
|
|
2748
|
+
"this",
|
|
2749
|
+
"that",
|
|
2750
|
+
"these",
|
|
2751
|
+
"those",
|
|
2752
|
+
"as",
|
|
2753
|
+
"not",
|
|
2754
|
+
"no",
|
|
2755
|
+
"can",
|
|
2756
|
+
"will",
|
|
2757
|
+
"just",
|
|
2758
|
+
"than",
|
|
2759
|
+
"too",
|
|
2760
|
+
"very",
|
|
2761
|
+
"would",
|
|
2762
|
+
"should",
|
|
2763
|
+
"could",
|
|
2764
|
+
"there",
|
|
2765
|
+
"here",
|
|
2766
|
+
"what",
|
|
2767
|
+
"which",
|
|
2768
|
+
"who",
|
|
2769
|
+
"whom"
|
|
2770
|
+
]);
|
|
2771
|
+
function analyzeKeywordDensity(text, options = {}) {
|
|
2772
|
+
if (!text || !text.trim()) return { error: "Input text is empty" };
|
|
2773
|
+
const topN = options.topN ?? 10;
|
|
2774
|
+
const minWordLength = options.minWordLength ?? 3;
|
|
2775
|
+
const ngramSize = options.ngramSize ?? 1;
|
|
2776
|
+
if (!Number.isInteger(topN) || topN <= 0) return { error: "topN must be a positive whole number" };
|
|
2777
|
+
if (!Number.isInteger(minWordLength) || minWordLength < 1) return { error: "minWordLength must be a positive whole number" };
|
|
2778
|
+
if (!Number.isInteger(ngramSize) || ngramSize < 1 || ngramSize > 3) return { error: "ngramSize must be 1, 2, or 3" };
|
|
2779
|
+
const tokens = text.toLowerCase().match(/[a-z0-9']+/g) ?? [];
|
|
2780
|
+
const totalWords = tokens.length;
|
|
2781
|
+
if (totalWords === 0) return { error: "No words found in input text" };
|
|
2782
|
+
if (totalWords < ngramSize) return { error: "Input text has fewer words than the requested phrase length" };
|
|
2783
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2784
|
+
for (let i = 0; i <= tokens.length - ngramSize; i++) {
|
|
2785
|
+
const phraseWords = tokens.slice(i, i + ngramSize);
|
|
2786
|
+
if (phraseWords.some((w) => w.length < minWordLength)) continue;
|
|
2787
|
+
if (ngramSize === 1 && KEYWORD_DENSITY_STOPWORDS.has(phraseWords[0])) continue;
|
|
2788
|
+
const phrase = phraseWords.join(" ");
|
|
2789
|
+
counts.set(phrase, (counts.get(phrase) ?? 0) + 1);
|
|
2790
|
+
}
|
|
2791
|
+
const keywords = Array.from(counts.entries()).map(([keyword, count]) => ({ keyword, count, density: Math.round(count / totalWords * 1e3) / 10 })).sort((a, b) => b.count - a.count || a.keyword.localeCompare(b.keyword)).slice(0, topN);
|
|
2792
|
+
return {
|
|
2793
|
+
totalWords,
|
|
2794
|
+
uniqueKeywords: counts.size,
|
|
2795
|
+
ngramSize,
|
|
2796
|
+
keywords
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2673
2799
|
var EMOJI_TABLE = [
|
|
2674
2800
|
{ emoji: "\u{1F600}", name: "grinning face", shortcode: "grinning", codepoint: "U+1F600", category: "Smileys & Emotion", keywords: ["happy", "smile"] },
|
|
2675
2801
|
{ emoji: "\u{1F603}", name: "grinning face with big eyes", shortcode: "smiley", codepoint: "U+1F603", category: "Smileys & Emotion", keywords: ["happy", "joy"] },
|
|
@@ -2970,4 +3096,4 @@ function getEmojiCategories() {
|
|
|
2970
3096
|
return Array.from(new Set(EMOJI_TABLE.map((e) => e.category)));
|
|
2971
3097
|
}
|
|
2972
3098
|
|
|
2973
|
-
export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, EMOJI_TABLE, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeSentenceLengths, analyzeText, applyOp, applyOps, calculateStringDistance, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, detectFillerWords, detectPassiveVoice, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getEmojiByCategory, getEmojiByChar, getEmojiByShortcode, getEmojiCategories, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, scoreReadability, searchEmoji, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
|
|
3099
|
+
export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, EMOJI_TABLE, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeKeywordDensity, analyzeSentenceLengths, analyzeText, applyOp, applyOps, calculateStringDistance, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, detectFillerWords, detectPassiveVoice, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getEmojiByCategory, getEmojiByChar, getEmojiByShortcode, getEmojiCategories, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, scoreReadability, searchEmoji, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
|