@utilix-tech/sdk 0.51.0 → 0.53.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 +21 -4
- package/dist/{chunk-BDQXYFTO.js → chunk-3KIUADK4.js} +49 -1
- package/dist/{chunk-JL7YTXRB.js → chunk-K4ZERKBD.js} +338 -2
- package/dist/{chunk-ZZJPD366.js → chunk-NKN656TQ.js} +44 -1
- package/dist/{code-KXoRsHtl.d.ts → code-B_gDkRAx.d.cts} +67 -2
- package/dist/{code-KXoRsHtl.d.cts → code-B_gDkRAx.d.ts} +67 -2
- package/dist/{data-BI_007dA.d.cts → data-CupeugaR.d.cts} +37 -2
- package/dist/{data-BI_007dA.d.ts → data-CupeugaR.d.ts} +37 -2
- package/dist/index.cjs +428 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/tools/code.cjs +336 -0
- package/dist/tools/code.d.cts +1 -1
- package/dist/tools/code.d.ts +1 -1
- package/dist/tools/code.js +1 -1
- package/dist/tools/data.cjs +48 -0
- package/dist/tools/data.d.cts +1 -1
- package/dist/tools/data.d.ts +1 -1
- package/dist/tools/data.js +1 -1
- package/dist/tools/units.cjs +43 -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-y30YVhqI.d.ts → units-p-1Ikx7l.d.cts} +39 -2
- package/dist/{units-y30YVhqI.d.cts → units-p-1Ikx7l.d.ts} +39 -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.53.0
|
|
6
|
+
- Add `calculateCreditUtilization` (credit-utilization-calculator): compute per-account and overall credit utilization (balance / limit) from one or more credit accounts, plus a qualitative tier matching common credit-scoring guidance.
|
|
7
|
+
- Add `analyzeCaptionSpeed` (caption-reading-speed-checker): parse an SRT or WebVTT file and report the words-per-minute reading speed of every cue, flagging ones that exceed common broadcast accessibility guidelines.
|
|
8
|
+
|
|
9
|
+
## 0.52.0
|
|
10
|
+
- Add `validateEditorConfig` (editorconfig-validator): parse an .editorconfig file into its root flag and glob sections, and flag structural mistakes against the EditorConfig spec.
|
|
11
|
+
- Add `validateTsconfig` (tsconfig-validator): parse a tsconfig.json file as JSONC and flag unknown keys, unknown compilerOptions, and type mismatches against a curated list of known options.
|
|
12
|
+
|
|
5
13
|
## 0.51.0
|
|
6
14
|
- Add `calculateGpa` (gpa-calculator): compute a weighted GPA from a list of courses, each with a letter grade and credit hours, using the standard 4.0-capped scale.
|
|
7
15
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**646 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)
|
|
@@ -204,7 +204,7 @@ analyzeKeywordDensity("machine learning models power machine learning systems");
|
|
|
204
204
|
import { parseCsv, csvToJson, validateYaml, resolveYamlAnchors, tomlToJson, jsonToToml,
|
|
205
205
|
formatXml, xmlToJson, jsonToXml, parseIni,
|
|
206
206
|
validateNdjson, formatNdjson, ndjsonToJsonArray, diffEnvExample,
|
|
207
|
-
parseSubtitles, convertSubtitles, shiftSubtitles, parseFrontMatter,
|
|
207
|
+
parseSubtitles, convertSubtitles, shiftSubtitles, analyzeCaptionSpeed, parseFrontMatter,
|
|
208
208
|
generateMarkdownToc, csvToSqlInsert, findCsvDuplicateRows, calculateMarkdownTaskListProgress } from "@utilix-tech/sdk/data";
|
|
209
209
|
|
|
210
210
|
// CSV
|
|
@@ -242,6 +242,10 @@ convertSubtitles("1\n00:00:01,000 --> 00:00:04,000\nHello there.\n", "vtt");
|
|
|
242
242
|
shiftSubtitles("1\n00:00:01,000 --> 00:00:04,000\nHi\n", -2.5);
|
|
243
243
|
// shifts every cue 2.5s earlier, clamping anything below zero to 00:00:00
|
|
244
244
|
|
|
245
|
+
// Caption reading speed: flag cues faster than ~180 WPM / ~20 chars/sec (both adjustable)
|
|
246
|
+
analyzeCaptionSpeed("1\n00:00:01,000 --> 00:00:02,000\nThis line is read far too fast for anyone to follow.\n");
|
|
247
|
+
// { cueCount: 1, averageWpm: 660, flaggedCount: 1, cues: [{ wpm: 660, exceedsWpm: true, ... }], ... }
|
|
248
|
+
|
|
245
249
|
// Markdown front matter: split a document into its YAML front matter and body
|
|
246
250
|
parseFrontMatter("---\ntitle: Hello World\ntags: [foo, bar]\n---\n# Body");
|
|
247
251
|
// { frontMatter: { title: "Hello World", tags: ["foo", "bar"] }, body: "# Body", hasFrontMatter: true, ... }
|
|
@@ -322,7 +326,7 @@ formatIso8601Duration(90061); // { iso: "P1DT1H1M1S", ... }
|
|
|
322
326
|
### `/units`: Conversions
|
|
323
327
|
|
|
324
328
|
```ts
|
|
325
|
-
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, calculateCashRounding, calculateMovingAverages, calculateGpa } from "@utilix-tech/sdk/units";
|
|
329
|
+
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, calculateCashRounding, calculateMovingAverages, calculateGpa, calculateCreditUtilization } from "@utilix-tech/sdk/units";
|
|
326
330
|
|
|
327
331
|
// File sizes
|
|
328
332
|
convertBytes(1073741824, "GB"); // 1
|
|
@@ -456,6 +460,10 @@ calculateMovingAverages([102, 104, 101, 108, 112], 3);
|
|
|
456
460
|
// Weighted GPA from a list of courses (letter grade + credit hours)
|
|
457
461
|
calculateGpa([{ name: "Calculus", grade: "A", credits: 4 }, { name: "History", grade: "B+", credits: 3 }]);
|
|
458
462
|
// { gpa: 3.7, totalCredits: 7, totalQualityPoints: 25.9, courses: [...] }
|
|
463
|
+
|
|
464
|
+
// Per-account and overall credit utilization, plus a qualitative tier
|
|
465
|
+
calculateCreditUtilization([{ label: "Visa", balance: 500, limit: 5000 }, { label: "Amex", balance: 1200, limit: 3000 }]);
|
|
466
|
+
// { overallUtilizationPercent: 21.25, overallTier: "good", totalBalance: 1700, totalLimit: 8000, accounts: [...] }
|
|
459
467
|
```
|
|
460
468
|
|
|
461
469
|
---
|
|
@@ -623,7 +631,8 @@ generateCspHeader({ "default-src": ["'self'"], "script-src": ["'self'", "cdn.exa
|
|
|
623
631
|
```ts
|
|
624
632
|
import { formatSql, minifySql, testRegex, formatHtml, formatGql,
|
|
625
633
|
detectDialect, splitStatements, lookupMime, parseGithubUrl,
|
|
626
|
-
detectRedos, testGitignorePatterns
|
|
634
|
+
detectRedos, testGitignorePatterns, validateEditorConfig,
|
|
635
|
+
validateTsconfig } from "@utilix-tech/sdk/code";
|
|
627
636
|
|
|
628
637
|
// SQL
|
|
629
638
|
formatSql("SELECT id,name FROM users WHERE active=1 ORDER BY name");
|
|
@@ -663,6 +672,14 @@ detectRedos("(a+)+");
|
|
|
663
672
|
// Test paths against a .gitignore file's patterns
|
|
664
673
|
testGitignorePatterns("node_modules/\n*.log", ["node_modules/foo.js", "debug.log", "src/index.js"]);
|
|
665
674
|
// [{ path: "node_modules/foo.js", ignored: true, matchedPattern: "node_modules/", matchedLine: 1 }, ...]
|
|
675
|
+
|
|
676
|
+
// Validate an .editorconfig file
|
|
677
|
+
validateEditorConfig("root = true\n\n[*]\nindent_style = space\nindent_size = 2\n");
|
|
678
|
+
// { root: true, sections: [{ glob: "*", properties: [...] }], issues: [], valid: true }
|
|
679
|
+
|
|
680
|
+
// Validate a tsconfig.json file (JSONC comments and trailing commas are stripped first)
|
|
681
|
+
validateTsconfig(JSON.stringify({ compilerOptions: { target: "ES2020", strict: true } }));
|
|
682
|
+
// { parsed: true, topLevelKeys: ["compilerOptions"], compilerOptionKeys: ["target", "strict"], issues: [], valid: true }
|
|
666
683
|
```
|
|
667
684
|
|
|
668
685
|
---
|
|
@@ -5,6 +5,7 @@ import { parse, stringify } from 'smol-toml';
|
|
|
5
5
|
// src/tools/data.ts
|
|
6
6
|
var data_exports = {};
|
|
7
7
|
__export(data_exports, {
|
|
8
|
+
analyzeCaptionSpeed: () => analyzeCaptionSpeed,
|
|
8
9
|
calculateMarkdownTaskListProgress: () => calculateMarkdownTaskListProgress,
|
|
9
10
|
convertSubtitles: () => convertSubtitles,
|
|
10
11
|
csvToJson: () => csvToJson,
|
|
@@ -1340,6 +1341,53 @@ function shiftSubtitles(input, offsetSeconds, target) {
|
|
|
1340
1341
|
warnings
|
|
1341
1342
|
};
|
|
1342
1343
|
}
|
|
1344
|
+
function analyzeCaptionSpeed(input, wpmThreshold = 180, cpsThreshold = 20) {
|
|
1345
|
+
if (!Number.isFinite(wpmThreshold) || wpmThreshold <= 0) {
|
|
1346
|
+
return { error: "wpmThreshold must be a finite number greater than zero" };
|
|
1347
|
+
}
|
|
1348
|
+
if (!Number.isFinite(cpsThreshold) || cpsThreshold <= 0) {
|
|
1349
|
+
return { error: "cpsThreshold must be a finite number greater than zero" };
|
|
1350
|
+
}
|
|
1351
|
+
const parsed = parseSubtitles(input);
|
|
1352
|
+
if ("error" in parsed) return parsed;
|
|
1353
|
+
const round1 = (n) => Math.round(n * 10) / 10;
|
|
1354
|
+
const cues = [];
|
|
1355
|
+
for (const cue of parsed.cues) {
|
|
1356
|
+
const text = cue.text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
1357
|
+
const durationSeconds = cue.end - cue.start;
|
|
1358
|
+
if (text.length === 0 || durationSeconds <= 0) continue;
|
|
1359
|
+
const wordCount = text.split(" ").filter(Boolean).length;
|
|
1360
|
+
const charCount = text.length;
|
|
1361
|
+
const wpm = wordCount / durationSeconds * 60;
|
|
1362
|
+
const charsPerSecond = charCount / durationSeconds;
|
|
1363
|
+
cues.push({
|
|
1364
|
+
index: cues.length + 1,
|
|
1365
|
+
start: round1(cue.start),
|
|
1366
|
+
end: round1(cue.end),
|
|
1367
|
+
text,
|
|
1368
|
+
durationSeconds: round1(durationSeconds),
|
|
1369
|
+
wordCount,
|
|
1370
|
+
charCount,
|
|
1371
|
+
wpm: round1(wpm),
|
|
1372
|
+
charsPerSecond: round1(charsPerSecond),
|
|
1373
|
+
exceedsWpm: wpm > wpmThreshold,
|
|
1374
|
+
exceedsCps: charsPerSecond > cpsThreshold
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
if (cues.length === 0) {
|
|
1378
|
+
return { error: "No cues with both text and a positive duration were found" };
|
|
1379
|
+
}
|
|
1380
|
+
const wpmValues = cues.map((c) => c.wpm);
|
|
1381
|
+
return {
|
|
1382
|
+
cueCount: cues.length,
|
|
1383
|
+
cues,
|
|
1384
|
+
averageWpm: round1(wpmValues.reduce((a, b) => a + b, 0) / wpmValues.length),
|
|
1385
|
+
maxWpm: round1(Math.max(...wpmValues)),
|
|
1386
|
+
flaggedCount: cues.filter((c) => c.exceedsWpm || c.exceedsCps).length,
|
|
1387
|
+
wpmThreshold,
|
|
1388
|
+
cpsThreshold
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1343
1391
|
function parseFrontMatterScalar(value) {
|
|
1344
1392
|
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1345
1393
|
return value.slice(1, -1);
|
|
@@ -1673,4 +1721,4 @@ function calculateMarkdownTaskListProgress(markdown) {
|
|
|
1673
1721
|
return { totalItems, completedItems, percentComplete, sections, items };
|
|
1674
1722
|
}
|
|
1675
1723
|
|
|
1676
|
-
export { calculateMarkdownTaskListProgress, convertSubtitles, csvToJson, csvToSqlInsert, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, findCsvDuplicateRows, 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, resolveYamlAnchors, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
|
|
1724
|
+
export { analyzeCaptionSpeed, calculateMarkdownTaskListProgress, convertSubtitles, csvToJson, csvToSqlInsert, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, findCsvDuplicateRows, 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, resolveYamlAnchors, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
|
|
@@ -55,7 +55,9 @@ __export(code_exports, {
|
|
|
55
55
|
testGitignorePatterns: () => testGitignorePatterns,
|
|
56
56
|
testPattern: () => testPattern,
|
|
57
57
|
testRegex: () => testRegex,
|
|
58
|
-
|
|
58
|
+
validateEditorConfig: () => validateEditorConfig,
|
|
59
|
+
validateEnvKey: () => validateEnvKey,
|
|
60
|
+
validateTsconfig: () => validateTsconfig
|
|
59
61
|
});
|
|
60
62
|
var ALL_FLAGS = ["g", "i", "m", "s", "u"];
|
|
61
63
|
function testRegex(pattern, flags, input) {
|
|
@@ -2940,5 +2942,339 @@ function testGitignorePatterns(gitignoreContent, paths) {
|
|
|
2940
2942
|
return { path, ignored, matchedPattern, matchedLine };
|
|
2941
2943
|
});
|
|
2942
2944
|
}
|
|
2945
|
+
var EDITORCONFIG_ENUM_PROPERTIES = {
|
|
2946
|
+
indent_style: ["tab", "space"],
|
|
2947
|
+
end_of_line: ["lf", "cr", "crlf"],
|
|
2948
|
+
charset: ["latin1", "utf-8", "utf-8-bom", "utf-16be", "utf-16le"],
|
|
2949
|
+
trim_trailing_whitespace: ["true", "false"],
|
|
2950
|
+
insert_final_newline: ["true", "false"]
|
|
2951
|
+
};
|
|
2952
|
+
var EDITORCONFIG_KNOWN_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2953
|
+
"indent_style",
|
|
2954
|
+
"indent_size",
|
|
2955
|
+
"tab_width",
|
|
2956
|
+
"end_of_line",
|
|
2957
|
+
"charset",
|
|
2958
|
+
"trim_trailing_whitespace",
|
|
2959
|
+
"insert_final_newline",
|
|
2960
|
+
"max_line_length",
|
|
2961
|
+
"root"
|
|
2962
|
+
]);
|
|
2963
|
+
var POSITIVE_INT_RE = /^[1-9][0-9]*$/;
|
|
2964
|
+
function validateEditorConfig(text) {
|
|
2965
|
+
if (!text || !text.trim()) return { error: "Input is empty" };
|
|
2966
|
+
const lines = text.split("\n");
|
|
2967
|
+
const issues = [];
|
|
2968
|
+
const sections = [];
|
|
2969
|
+
let root = false;
|
|
2970
|
+
let rootSeen = false;
|
|
2971
|
+
let currentSection = null;
|
|
2972
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2973
|
+
const lineNum = i + 1;
|
|
2974
|
+
const trimmed = lines[i].trim();
|
|
2975
|
+
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith(";")) continue;
|
|
2976
|
+
const sectionMatch = trimmed.match(/^\[(.*)\]$/);
|
|
2977
|
+
if (sectionMatch) {
|
|
2978
|
+
const glob = sectionMatch[1];
|
|
2979
|
+
if (!glob) {
|
|
2980
|
+
issues.push({ severity: "warning", line: lineNum, message: 'Section header is empty ("[]" matches no files)' });
|
|
2981
|
+
}
|
|
2982
|
+
if (sections.some((s) => s.glob === glob)) {
|
|
2983
|
+
issues.push({ severity: "warning", line: lineNum, message: `Duplicate section "[${glob}]" (an earlier section already uses this exact glob)` });
|
|
2984
|
+
}
|
|
2985
|
+
currentSection = { glob, line: lineNum, properties: [] };
|
|
2986
|
+
sections.push(currentSection);
|
|
2987
|
+
continue;
|
|
2988
|
+
}
|
|
2989
|
+
const eqIdx = trimmed.indexOf("=");
|
|
2990
|
+
if (eqIdx === -1) {
|
|
2991
|
+
issues.push({ severity: "error", line: lineNum, message: `Malformed line (missing '='): "${trimmed}"` });
|
|
2992
|
+
continue;
|
|
2993
|
+
}
|
|
2994
|
+
const rawKey = trimmed.slice(0, eqIdx).trim();
|
|
2995
|
+
const key = rawKey.toLowerCase();
|
|
2996
|
+
const rawValue = trimmed.slice(eqIdx + 1).trim();
|
|
2997
|
+
const normalizedValue = rawValue.toLowerCase();
|
|
2998
|
+
if (!rawKey) {
|
|
2999
|
+
issues.push({ severity: "error", line: lineNum, message: "Property is missing a name" });
|
|
3000
|
+
continue;
|
|
3001
|
+
}
|
|
3002
|
+
if (key === "root") {
|
|
3003
|
+
if (sections.length > 0) {
|
|
3004
|
+
issues.push({ severity: "error", line: lineNum, message: `"root" must appear before any section, in the file's preamble` });
|
|
3005
|
+
} else if (rootSeen) {
|
|
3006
|
+
issues.push({ severity: "warning", line: lineNum, message: 'Duplicate "root" declaration' });
|
|
3007
|
+
} else if (normalizedValue !== "true" && normalizedValue !== "false") {
|
|
3008
|
+
issues.push({ severity: "error", line: lineNum, message: `"root" must be "true" or "false", got "${rawValue}"` });
|
|
3009
|
+
} else {
|
|
3010
|
+
root = normalizedValue === "true";
|
|
3011
|
+
}
|
|
3012
|
+
rootSeen = true;
|
|
3013
|
+
continue;
|
|
3014
|
+
}
|
|
3015
|
+
if (!currentSection) {
|
|
3016
|
+
issues.push({ severity: "error", line: lineNum, message: `Property "${rawKey}" found before any section header` });
|
|
3017
|
+
continue;
|
|
3018
|
+
}
|
|
3019
|
+
if (currentSection.properties.some((p) => p.key === key)) {
|
|
3020
|
+
issues.push({ severity: "warning", line: lineNum, message: `Duplicate property "${key}" in section "[${currentSection.glob}]"` });
|
|
3021
|
+
}
|
|
3022
|
+
currentSection.properties.push({ key, value: rawValue, line: lineNum });
|
|
3023
|
+
if (!EDITORCONFIG_KNOWN_PROPERTIES.has(key)) {
|
|
3024
|
+
issues.push({ severity: "warning", line: lineNum, message: `Unknown property "${key}"` });
|
|
3025
|
+
continue;
|
|
3026
|
+
}
|
|
3027
|
+
if (key in EDITORCONFIG_ENUM_PROPERTIES) {
|
|
3028
|
+
if (!EDITORCONFIG_ENUM_PROPERTIES[key].includes(normalizedValue)) {
|
|
3029
|
+
issues.push({ severity: "error", line: lineNum, message: `"${key}" must be one of ${EDITORCONFIG_ENUM_PROPERTIES[key].join(", ")}, got "${rawValue}"` });
|
|
3030
|
+
}
|
|
3031
|
+
} else if (key === "indent_size") {
|
|
3032
|
+
if (normalizedValue !== "tab" && !POSITIVE_INT_RE.test(rawValue)) {
|
|
3033
|
+
issues.push({ severity: "error", line: lineNum, message: `"indent_size" must be a positive integer or "tab", got "${rawValue}"` });
|
|
3034
|
+
}
|
|
3035
|
+
} else if (key === "tab_width") {
|
|
3036
|
+
if (!POSITIVE_INT_RE.test(rawValue)) {
|
|
3037
|
+
issues.push({ severity: "error", line: lineNum, message: `"tab_width" must be a positive integer, got "${rawValue}"` });
|
|
3038
|
+
}
|
|
3039
|
+
} else if (key === "max_line_length") {
|
|
3040
|
+
if (normalizedValue !== "off" && !POSITIVE_INT_RE.test(rawValue)) {
|
|
3041
|
+
issues.push({ severity: "error", line: lineNum, message: `"max_line_length" must be a positive integer or "off", got "${rawValue}"` });
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
if (sections.length === 0 && !rootSeen) {
|
|
3046
|
+
issues.push({ severity: "warning", line: 1, message: "File has no section headers and no root declaration" });
|
|
3047
|
+
}
|
|
3048
|
+
const valid = !issues.some((i) => i.severity === "error");
|
|
3049
|
+
return { root, sections, issues, valid };
|
|
3050
|
+
}
|
|
3051
|
+
function stripJsonComments(input) {
|
|
3052
|
+
let out = "";
|
|
3053
|
+
let i = 0;
|
|
3054
|
+
const n = input.length;
|
|
3055
|
+
let inString = false;
|
|
3056
|
+
while (i < n) {
|
|
3057
|
+
const c = input[i];
|
|
3058
|
+
const next = input[i + 1];
|
|
3059
|
+
if (inString) {
|
|
3060
|
+
out += c;
|
|
3061
|
+
if (c === "\\") {
|
|
3062
|
+
out += next ?? "";
|
|
3063
|
+
i += 2;
|
|
3064
|
+
continue;
|
|
3065
|
+
}
|
|
3066
|
+
if (c === '"') inString = false;
|
|
3067
|
+
i++;
|
|
3068
|
+
continue;
|
|
3069
|
+
}
|
|
3070
|
+
if (c === '"') {
|
|
3071
|
+
inString = true;
|
|
3072
|
+
out += c;
|
|
3073
|
+
i++;
|
|
3074
|
+
continue;
|
|
3075
|
+
}
|
|
3076
|
+
if (c === "/" && next === "/") {
|
|
3077
|
+
while (i < n && input[i] !== "\n") i++;
|
|
3078
|
+
continue;
|
|
3079
|
+
}
|
|
3080
|
+
if (c === "/" && next === "*") {
|
|
3081
|
+
i += 2;
|
|
3082
|
+
while (i < n && !(input[i] === "*" && input[i + 1] === "/")) {
|
|
3083
|
+
out += input[i] === "\n" ? "\n" : "";
|
|
3084
|
+
i++;
|
|
3085
|
+
}
|
|
3086
|
+
i += 2;
|
|
3087
|
+
continue;
|
|
3088
|
+
}
|
|
3089
|
+
out += c;
|
|
3090
|
+
i++;
|
|
3091
|
+
}
|
|
3092
|
+
return out;
|
|
3093
|
+
}
|
|
3094
|
+
function stripTrailingCommas(input) {
|
|
3095
|
+
return input.replace(/,(\s*[}\]])/g, "$1");
|
|
3096
|
+
}
|
|
3097
|
+
var TSCONFIG_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3098
|
+
"compilerOptions",
|
|
3099
|
+
"files",
|
|
3100
|
+
"include",
|
|
3101
|
+
"exclude",
|
|
3102
|
+
"extends",
|
|
3103
|
+
"references",
|
|
3104
|
+
"compileOnSave",
|
|
3105
|
+
"typeAcquisition",
|
|
3106
|
+
"watchOptions",
|
|
3107
|
+
"buildOptions",
|
|
3108
|
+
"$schema"
|
|
3109
|
+
]);
|
|
3110
|
+
var TSCONFIG_ENUM_OPTIONS = {
|
|
3111
|
+
target: ["es3", "es5", "es6", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020", "es2021", "es2022", "es2023", "esnext"],
|
|
3112
|
+
module: ["none", "commonjs", "amd", "umd", "system", "es6", "es2015", "es2020", "es2022", "esnext", "node16", "nodenext", "node18", "preserve"],
|
|
3113
|
+
moduleResolution: ["classic", "node", "node10", "node16", "nodenext", "bundler"],
|
|
3114
|
+
moduleDetection: ["legacy", "auto", "force"],
|
|
3115
|
+
jsx: ["preserve", "react", "react-jsx", "react-jsxdev", "react-native"],
|
|
3116
|
+
newLine: ["crlf", "lf"],
|
|
3117
|
+
importsNotUsedAsValues: ["remove", "preserve", "error"]
|
|
3118
|
+
};
|
|
3119
|
+
var TSCONFIG_BOOLEAN_OPTIONS = /* @__PURE__ */ new Set([
|
|
3120
|
+
"allowJs",
|
|
3121
|
+
"checkJs",
|
|
3122
|
+
"strict",
|
|
3123
|
+
"noImplicitAny",
|
|
3124
|
+
"strictNullChecks",
|
|
3125
|
+
"strictFunctionTypes",
|
|
3126
|
+
"strictBindCallApply",
|
|
3127
|
+
"strictPropertyInitialization",
|
|
3128
|
+
"noImplicitThis",
|
|
3129
|
+
"useUnknownInCatchVariables",
|
|
3130
|
+
"alwaysStrict",
|
|
3131
|
+
"noUnusedLocals",
|
|
3132
|
+
"noUnusedParameters",
|
|
3133
|
+
"exactOptionalPropertyTypes",
|
|
3134
|
+
"noImplicitReturns",
|
|
3135
|
+
"noFallthroughCasesInSwitch",
|
|
3136
|
+
"noUncheckedIndexedAccess",
|
|
3137
|
+
"noImplicitOverride",
|
|
3138
|
+
"noPropertyAccessFromIndexSignature",
|
|
3139
|
+
"esModuleInterop",
|
|
3140
|
+
"allowSyntheticDefaultImports",
|
|
3141
|
+
"forceConsistentCasingInFileNames",
|
|
3142
|
+
"isolatedModules",
|
|
3143
|
+
"verbatimModuleSyntax",
|
|
3144
|
+
"declaration",
|
|
3145
|
+
"declarationMap",
|
|
3146
|
+
"emitDeclarationOnly",
|
|
3147
|
+
"sourceMap",
|
|
3148
|
+
"inlineSourceMap",
|
|
3149
|
+
"inlineSources",
|
|
3150
|
+
"noEmit",
|
|
3151
|
+
"noEmitOnError",
|
|
3152
|
+
"preserveConstEnums",
|
|
3153
|
+
"removeComments",
|
|
3154
|
+
"skipLibCheck",
|
|
3155
|
+
"composite",
|
|
3156
|
+
"incremental",
|
|
3157
|
+
"experimentalDecorators",
|
|
3158
|
+
"emitDecoratorMetadata",
|
|
3159
|
+
"resolveJsonModule",
|
|
3160
|
+
"allowUmdGlobalAccess",
|
|
3161
|
+
"downlevelIteration",
|
|
3162
|
+
"importHelpers",
|
|
3163
|
+
"preserveSymlinks",
|
|
3164
|
+
"allowUnreachableCode",
|
|
3165
|
+
"allowUnusedLabels",
|
|
3166
|
+
"disableSizeLimit",
|
|
3167
|
+
"noResolve",
|
|
3168
|
+
"skipDefaultLibCheck",
|
|
3169
|
+
"suppressImplicitAnyIndexErrors"
|
|
3170
|
+
]);
|
|
3171
|
+
var TSCONFIG_STRING_OPTIONS = /* @__PURE__ */ new Set([
|
|
3172
|
+
"outDir",
|
|
3173
|
+
"rootDir",
|
|
3174
|
+
"baseUrl",
|
|
3175
|
+
"outFile",
|
|
3176
|
+
"declarationDir",
|
|
3177
|
+
"tsBuildInfoFile",
|
|
3178
|
+
"jsxFactory",
|
|
3179
|
+
"jsxFragmentFactory",
|
|
3180
|
+
"jsxImportSource"
|
|
3181
|
+
]);
|
|
3182
|
+
var TSCONFIG_ARRAY_OPTIONS = /* @__PURE__ */ new Set(["lib", "types", "typeRoots", "rootDirs"]);
|
|
3183
|
+
function validateTsconfig(text) {
|
|
3184
|
+
if (!text || !text.trim()) return { error: "Input is empty" };
|
|
3185
|
+
const stripped = stripTrailingCommas(stripJsonComments(text));
|
|
3186
|
+
let parsed;
|
|
3187
|
+
try {
|
|
3188
|
+
parsed = JSON.parse(stripped);
|
|
3189
|
+
} catch (e) {
|
|
3190
|
+
return { error: `Invalid JSON: ${e.message}` };
|
|
3191
|
+
}
|
|
3192
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3193
|
+
return { error: "Root of tsconfig.json must be an object" };
|
|
3194
|
+
}
|
|
3195
|
+
const obj = parsed;
|
|
3196
|
+
const issues = [];
|
|
3197
|
+
const topLevelKeys = Object.keys(obj);
|
|
3198
|
+
for (const key of topLevelKeys) {
|
|
3199
|
+
if (!TSCONFIG_TOP_LEVEL_KEYS.has(key)) {
|
|
3200
|
+
issues.push({ severity: "warning", path: key, message: `Unknown top-level key "${key}"` });
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
for (const key of ["files", "include", "exclude"]) {
|
|
3204
|
+
if (key in obj) {
|
|
3205
|
+
const v = obj[key];
|
|
3206
|
+
if (!Array.isArray(v) || !v.every((x) => typeof x === "string")) {
|
|
3207
|
+
issues.push({ severity: "error", path: key, message: `"${key}" must be an array of strings` });
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
if ("extends" in obj) {
|
|
3212
|
+
const v = obj.extends;
|
|
3213
|
+
const validExtends = typeof v === "string" || Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
3214
|
+
if (!validExtends) {
|
|
3215
|
+
issues.push({ severity: "error", path: "extends", message: '"extends" must be a string or an array of strings' });
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
if ("references" in obj) {
|
|
3219
|
+
const v = obj.references;
|
|
3220
|
+
const validRefs = Array.isArray(v) && v.every((r) => typeof r === "object" && r !== null && typeof r.path === "string");
|
|
3221
|
+
if (!validRefs) {
|
|
3222
|
+
issues.push({ severity: "error", path: "references", message: '"references" must be an array of objects with a "path" string' });
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
let compilerOptionKeys = [];
|
|
3226
|
+
if ("compilerOptions" in obj) {
|
|
3227
|
+
const co = obj.compilerOptions;
|
|
3228
|
+
if (typeof co !== "object" || co === null || Array.isArray(co)) {
|
|
3229
|
+
issues.push({ severity: "error", path: "compilerOptions", message: '"compilerOptions" must be an object' });
|
|
3230
|
+
} else {
|
|
3231
|
+
const coObj = co;
|
|
3232
|
+
compilerOptionKeys = Object.keys(coObj);
|
|
3233
|
+
for (const key of compilerOptionKeys) {
|
|
3234
|
+
const value = coObj[key];
|
|
3235
|
+
const path = `compilerOptions.${key}`;
|
|
3236
|
+
if (key === "paths") {
|
|
3237
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3238
|
+
issues.push({ severity: "error", path, message: '"paths" must be an object mapping patterns to arrays of strings' });
|
|
3239
|
+
} else {
|
|
3240
|
+
for (const [k, v] of Object.entries(value)) {
|
|
3241
|
+
if (!Array.isArray(v) || !v.every((x) => typeof x === "string")) {
|
|
3242
|
+
issues.push({ severity: "error", path: `${path}.${k}`, message: `"paths.${k}" must be an array of strings` });
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
continue;
|
|
3247
|
+
}
|
|
3248
|
+
if (key in TSCONFIG_ENUM_OPTIONS) {
|
|
3249
|
+
if (typeof value !== "string" || !TSCONFIG_ENUM_OPTIONS[key].includes(value.toLowerCase())) {
|
|
3250
|
+
issues.push({ severity: "error", path, message: `"${key}" must be one of ${TSCONFIG_ENUM_OPTIONS[key].join(", ")}, got ${JSON.stringify(value)}` });
|
|
3251
|
+
}
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
3254
|
+
if (TSCONFIG_BOOLEAN_OPTIONS.has(key)) {
|
|
3255
|
+
if (typeof value !== "boolean") {
|
|
3256
|
+
issues.push({ severity: "error", path, message: `"${key}" must be a boolean, got ${JSON.stringify(value)}` });
|
|
3257
|
+
}
|
|
3258
|
+
continue;
|
|
3259
|
+
}
|
|
3260
|
+
if (TSCONFIG_STRING_OPTIONS.has(key)) {
|
|
3261
|
+
if (typeof value !== "string") {
|
|
3262
|
+
issues.push({ severity: "error", path, message: `"${key}" must be a string, got ${JSON.stringify(value)}` });
|
|
3263
|
+
}
|
|
3264
|
+
continue;
|
|
3265
|
+
}
|
|
3266
|
+
if (TSCONFIG_ARRAY_OPTIONS.has(key)) {
|
|
3267
|
+
if (!Array.isArray(value) || !value.every((x) => typeof x === "string")) {
|
|
3268
|
+
issues.push({ severity: "error", path, message: `"${key}" must be an array of strings, got ${JSON.stringify(value)}` });
|
|
3269
|
+
}
|
|
3270
|
+
continue;
|
|
3271
|
+
}
|
|
3272
|
+
issues.push({ severity: "warning", path, message: `Unknown compilerOption "${key}"` });
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
const valid = !issues.some((i) => i.severity === "error");
|
|
3277
|
+
return { parsed: true, topLevelKeys, compilerOptionKeys, issues, valid };
|
|
3278
|
+
}
|
|
2943
3279
|
|
|
2944
|
-
export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, 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, testGitignorePatterns, testPattern, testRegex, validateEnvKey };
|
|
3280
|
+
export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, 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, testGitignorePatterns, testPattern, testRegex, validateEditorConfig, validateEnvKey, validateTsconfig };
|
|
@@ -27,6 +27,7 @@ __export(units_exports, {
|
|
|
27
27
|
calculateCdMaturity: () => calculateCdMaturity,
|
|
28
28
|
calculateChange: () => calculateChange,
|
|
29
29
|
calculateCompoundInterest: () => calculateCompoundInterest,
|
|
30
|
+
calculateCreditUtilization: () => calculateCreditUtilization,
|
|
30
31
|
calculateDepreciationSchedule: () => calculateDepreciationSchedule,
|
|
31
32
|
calculateDiscount: () => calculateDiscount,
|
|
32
33
|
calculateEmi: () => calculateEmi,
|
|
@@ -2190,5 +2191,47 @@ function calculateGpa(courses) {
|
|
|
2190
2191
|
gpa: round22(totalQualityPoints / totalCredits)
|
|
2191
2192
|
};
|
|
2192
2193
|
}
|
|
2194
|
+
function _classifyUtilization(percent) {
|
|
2195
|
+
if (percent < 10) return "excellent";
|
|
2196
|
+
if (percent < 30) return "good";
|
|
2197
|
+
if (percent < 50) return "fair";
|
|
2198
|
+
return "poor";
|
|
2199
|
+
}
|
|
2200
|
+
function calculateCreditUtilization(accounts) {
|
|
2201
|
+
if (!Array.isArray(accounts) || accounts.length === 0) {
|
|
2202
|
+
return { error: "accounts must be a non-empty array" };
|
|
2203
|
+
}
|
|
2204
|
+
const round22 = (n) => Math.round(n * 100) / 100;
|
|
2205
|
+
let totalBalance = 0;
|
|
2206
|
+
let totalLimit = 0;
|
|
2207
|
+
const results = [];
|
|
2208
|
+
for (let i = 0; i < accounts.length; i++) {
|
|
2209
|
+
const account = accounts[i];
|
|
2210
|
+
if (typeof account.balance !== "number" || !Number.isFinite(account.balance) || account.balance < 0) {
|
|
2211
|
+
return { error: `account ${i + 1}: balance must be a finite, non-negative number` };
|
|
2212
|
+
}
|
|
2213
|
+
if (typeof account.limit !== "number" || !Number.isFinite(account.limit) || account.limit <= 0) {
|
|
2214
|
+
return { error: `account ${i + 1}: limit must be a finite number greater than zero` };
|
|
2215
|
+
}
|
|
2216
|
+
const utilizationPercent = round22(account.balance / account.limit * 100);
|
|
2217
|
+
totalBalance += account.balance;
|
|
2218
|
+
totalLimit += account.limit;
|
|
2219
|
+
results.push({
|
|
2220
|
+
label: account.label?.trim() || `Account ${i + 1}`,
|
|
2221
|
+
balance: account.balance,
|
|
2222
|
+
limit: account.limit,
|
|
2223
|
+
utilizationPercent,
|
|
2224
|
+
tier: _classifyUtilization(utilizationPercent)
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
const overallUtilizationPercent = round22(totalBalance / totalLimit * 100);
|
|
2228
|
+
return {
|
|
2229
|
+
accounts: results,
|
|
2230
|
+
totalBalance: round22(totalBalance),
|
|
2231
|
+
totalLimit: round22(totalLimit),
|
|
2232
|
+
overallUtilizationPercent,
|
|
2233
|
+
overallTier: _classifyUtilization(overallUtilizationPercent)
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2193
2236
|
|
|
2194
|
-
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, GPA_GRADE_POINTS, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCashBreakdown, calculateCashRounding, calculateCdMaturity, calculateChange, calculateCompoundInterest, calculateDepreciationSchedule, calculateDiscount, calculateEmi, calculateGpa, calculateLoan, calculateMarginMarkup, calculateMovingAverages, 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 };
|
|
2237
|
+
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, GPA_GRADE_POINTS, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCashBreakdown, calculateCashRounding, calculateCdMaturity, calculateChange, calculateCompoundInterest, calculateCreditUtilization, calculateDepreciationSchedule, calculateDiscount, calculateEmi, calculateGpa, calculateLoan, calculateMarginMarkup, calculateMovingAverages, 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 };
|