@utilix-tech/sdk 0.2.0 → 0.3.1

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 (37) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +62 -25
  3. package/SECURITY.md +16 -0
  4. package/dist/{chunk-OKSWDVOM.js → chunk-GX7H6TAX.js} +1 -1
  5. package/dist/{chunk-W4UBLYFU.js → chunk-HFRTZE7T.js} +2 -2
  6. package/dist/{chunk-ROTPLW7T.js → chunk-IPR7FSX4.js} +2 -2
  7. package/dist/chunk-N7C52YGL.js +134 -0
  8. package/dist/{chunk-XST6X3HT.js → chunk-QJE743LY.js} +10 -10
  9. package/dist/{chunk-NSOARQCM.js → chunk-V5S6OJ4A.js} +14 -14
  10. package/dist/{chunk-XXYZLLHI.js → chunk-YBBYFAOV.js} +167 -1
  11. package/dist/index.cjs +327 -29
  12. package/dist/index.d.cts +2 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +7 -6
  15. package/dist/media-DF2cx3pK.d.cts +28 -0
  16. package/dist/media-DF2cx3pK.d.ts +28 -0
  17. package/dist/{text-DqAjPtQ0.d.cts → text-CI7JAl7F.d.cts} +28 -2
  18. package/dist/{text-DqAjPtQ0.d.ts → text-CI7JAl7F.d.ts} +28 -2
  19. package/dist/tools/api.cjs +2 -2
  20. package/dist/tools/api.js +1 -1
  21. package/dist/tools/code.cjs +14 -14
  22. package/dist/tools/code.js +1 -1
  23. package/dist/tools/encoding.cjs +2 -2
  24. package/dist/tools/encoding.js +1 -1
  25. package/dist/tools/media.cjs +130 -0
  26. package/dist/tools/media.d.cts +1 -0
  27. package/dist/tools/media.d.ts +1 -0
  28. package/dist/tools/media.js +2 -0
  29. package/dist/tools/misc.cjs +1 -1
  30. package/dist/tools/misc.js +1 -1
  31. package/dist/tools/text.cjs +166 -0
  32. package/dist/tools/text.d.cts +1 -1
  33. package/dist/tools/text.d.ts +1 -1
  34. package/dist/tools/text.js +1 -1
  35. package/dist/tools/units.cjs +10 -10
  36. package/dist/tools/units.js +1 -1
  37. package/package.json +23 -4
@@ -20,6 +20,7 @@ __export(text_exports, {
20
20
  csvToHtml: () => csvToHtml,
21
21
  csvToMarkdown: () => csvToMarkdown,
22
22
  detectDelimiter: () => detectDelimiter,
23
+ detectPassiveVoice: () => detectPassiveVoice,
23
24
  diffLines: () => diffLines,
24
25
  diffLinesSimple: () => diffLinesSimple,
25
26
  diffStats: () => diffStats,
@@ -2223,5 +2224,170 @@ function getMorseTiming(morse) {
2223
2224
  }
2224
2225
  return result;
2225
2226
  }
2227
+ var BE_VERBS = /* @__PURE__ */ new Set(["am", "is", "are", "was", "were", "be", "been", "being"]);
2228
+ var IRREGULAR_PARTICIPLES = /* @__PURE__ */ new Set([
2229
+ "awoken",
2230
+ "been",
2231
+ "become",
2232
+ "begun",
2233
+ "bent",
2234
+ "bet",
2235
+ "bitten",
2236
+ "bled",
2237
+ "blown",
2238
+ "born",
2239
+ "bought",
2240
+ "bound",
2241
+ "bred",
2242
+ "broken",
2243
+ "brought",
2244
+ "built",
2245
+ "burnt",
2246
+ "burst",
2247
+ "caught",
2248
+ "chosen",
2249
+ "clung",
2250
+ "come",
2251
+ "cost",
2252
+ "crept",
2253
+ "cut",
2254
+ "dealt",
2255
+ "dived",
2256
+ "done",
2257
+ "drawn",
2258
+ "dreamt",
2259
+ "driven",
2260
+ "drunk",
2261
+ "dug",
2262
+ "eaten",
2263
+ "fallen",
2264
+ "fed",
2265
+ "felt",
2266
+ "fit",
2267
+ "fled",
2268
+ "flown",
2269
+ "forbidden",
2270
+ "forgiven",
2271
+ "forgotten",
2272
+ "fought",
2273
+ "found",
2274
+ "frozen",
2275
+ "given",
2276
+ "gone",
2277
+ "gotten",
2278
+ "grown",
2279
+ "hidden",
2280
+ "held",
2281
+ "hung",
2282
+ "hurt",
2283
+ "kept",
2284
+ "knelt",
2285
+ "knit",
2286
+ "known",
2287
+ "laid",
2288
+ "lain",
2289
+ "led",
2290
+ "left",
2291
+ "lent",
2292
+ "let",
2293
+ "lit",
2294
+ "lost",
2295
+ "made",
2296
+ "meant",
2297
+ "met",
2298
+ "mistaken",
2299
+ "paid",
2300
+ "proven",
2301
+ "put",
2302
+ "quit",
2303
+ "read",
2304
+ "rid",
2305
+ "ridden",
2306
+ "risen",
2307
+ "run",
2308
+ "said",
2309
+ "sat",
2310
+ "sawn",
2311
+ "seen",
2312
+ "sent",
2313
+ "set",
2314
+ "sewn",
2315
+ "shaken",
2316
+ "shed",
2317
+ "shone",
2318
+ "shot",
2319
+ "shown",
2320
+ "shrunk",
2321
+ "shut",
2322
+ "sold",
2323
+ "sought",
2324
+ "sown",
2325
+ "spent",
2326
+ "spoken",
2327
+ "spread",
2328
+ "sprung",
2329
+ "stolen",
2330
+ "stood",
2331
+ "stuck",
2332
+ "stung",
2333
+ "struck",
2334
+ "strung",
2335
+ "sung",
2336
+ "sunk",
2337
+ "swept",
2338
+ "sworn",
2339
+ "swum",
2340
+ "swung",
2341
+ "taken",
2342
+ "taught",
2343
+ "thought",
2344
+ "thrown",
2345
+ "told",
2346
+ "torn",
2347
+ "understood",
2348
+ "upset",
2349
+ "woken",
2350
+ "won",
2351
+ "worn",
2352
+ "wound",
2353
+ "woven",
2354
+ "written"
2355
+ ]);
2356
+ function isPastParticiple(word) {
2357
+ const w = word.toLowerCase();
2358
+ if (IRREGULAR_PARTICIPLES.has(w)) return true;
2359
+ return w.length > 3 && /^[a-z]+ed$/.test(w);
2360
+ }
2361
+ function splitIntoSentences(text) {
2362
+ const matches = text.match(/[^.!?]+[.!?]*/g);
2363
+ if (!matches) return [];
2364
+ return matches.map((s) => s.trim()).filter((s) => s.length > 0);
2365
+ }
2366
+ function detectPassiveVoice(text) {
2367
+ const sentences = splitIntoSentences(text);
2368
+ const analyzed = sentences.map((sentence, index) => {
2369
+ const words = sentence.match(/[a-zA-Z']+/g) ?? [];
2370
+ const matches = [];
2371
+ for (let i = 0; i < words.length; i++) {
2372
+ if (!BE_VERBS.has(words[i].toLowerCase())) continue;
2373
+ let j = i + 1;
2374
+ let adverbCount = 0;
2375
+ while (j < words.length && adverbCount < 2 && /ly$/i.test(words[j]) && !isPastParticiple(words[j])) {
2376
+ j++;
2377
+ adverbCount++;
2378
+ }
2379
+ if (j < words.length && isPastParticiple(words[j])) {
2380
+ const hasAgent = words.slice(j + 1, j + 5).some((w) => w.toLowerCase() === "by");
2381
+ matches.push({ phrase: words.slice(i, j + 1).join(" "), hasAgent });
2382
+ i = j;
2383
+ }
2384
+ }
2385
+ return { index, text: sentence, isPassive: matches.length > 0, matches };
2386
+ });
2387
+ const totalSentences = analyzed.length;
2388
+ const passiveSentences = analyzed.filter((s) => s.isPassive).length;
2389
+ const passivePercent = totalSentences > 0 ? Math.round(passiveSentences / totalSentences * 1e3) / 10 : 0;
2390
+ return { sentences: analyzed, totalSentences, passiveSentences, passivePercent };
2391
+ }
2226
2392
 
2227
- export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeText, applyOp, applyOps, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
2393
+ export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeText, applyOp, applyOps, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, detectPassiveVoice, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
package/dist/index.cjs CHANGED
@@ -1333,7 +1333,7 @@ function decodeBase64(input, variant = "standard") {
1333
1333
  const output = bytes.toString("utf8");
1334
1334
  return { ok: true, output, outputBytes: bytes.length };
1335
1335
  } catch {
1336
- return { ok: false, error: "Invalid Base64 \u2014 check the input and variant setting" };
1336
+ return { ok: false, error: "Invalid Base64: check the input and variant setting" };
1337
1337
  }
1338
1338
  }
1339
1339
  function encodeUrl(input, mode = "component") {
@@ -1352,7 +1352,7 @@ function decodeUrl(input, mode = "component") {
1352
1352
  const output = mode === "component" ? decodeURIComponent(trimmed) : decodeURI(trimmed);
1353
1353
  return { ok: true, output, changed: output !== trimmed };
1354
1354
  } catch {
1355
- return { ok: false, error: "Invalid percent-encoding \u2014 check the input" };
1355
+ return { ok: false, error: "Invalid percent-encoding: check the input" };
1356
1356
  }
1357
1357
  }
1358
1358
  function diffSegments(original, encoded) {
@@ -1820,6 +1820,7 @@ __export(text_exports, {
1820
1820
  csvToHtml: () => csvToHtml,
1821
1821
  csvToMarkdown: () => csvToMarkdown,
1822
1822
  detectDelimiter: () => detectDelimiter,
1823
+ detectPassiveVoice: () => detectPassiveVoice,
1823
1824
  diffLines: () => diffLines,
1824
1825
  diffLinesSimple: () => diffLinesSimple,
1825
1826
  diffStats: () => diffStats,
@@ -4023,6 +4024,171 @@ function getMorseTiming(morse) {
4023
4024
  }
4024
4025
  return result;
4025
4026
  }
4027
+ var BE_VERBS = /* @__PURE__ */ new Set(["am", "is", "are", "was", "were", "be", "been", "being"]);
4028
+ var IRREGULAR_PARTICIPLES = /* @__PURE__ */ new Set([
4029
+ "awoken",
4030
+ "been",
4031
+ "become",
4032
+ "begun",
4033
+ "bent",
4034
+ "bet",
4035
+ "bitten",
4036
+ "bled",
4037
+ "blown",
4038
+ "born",
4039
+ "bought",
4040
+ "bound",
4041
+ "bred",
4042
+ "broken",
4043
+ "brought",
4044
+ "built",
4045
+ "burnt",
4046
+ "burst",
4047
+ "caught",
4048
+ "chosen",
4049
+ "clung",
4050
+ "come",
4051
+ "cost",
4052
+ "crept",
4053
+ "cut",
4054
+ "dealt",
4055
+ "dived",
4056
+ "done",
4057
+ "drawn",
4058
+ "dreamt",
4059
+ "driven",
4060
+ "drunk",
4061
+ "dug",
4062
+ "eaten",
4063
+ "fallen",
4064
+ "fed",
4065
+ "felt",
4066
+ "fit",
4067
+ "fled",
4068
+ "flown",
4069
+ "forbidden",
4070
+ "forgiven",
4071
+ "forgotten",
4072
+ "fought",
4073
+ "found",
4074
+ "frozen",
4075
+ "given",
4076
+ "gone",
4077
+ "gotten",
4078
+ "grown",
4079
+ "hidden",
4080
+ "held",
4081
+ "hung",
4082
+ "hurt",
4083
+ "kept",
4084
+ "knelt",
4085
+ "knit",
4086
+ "known",
4087
+ "laid",
4088
+ "lain",
4089
+ "led",
4090
+ "left",
4091
+ "lent",
4092
+ "let",
4093
+ "lit",
4094
+ "lost",
4095
+ "made",
4096
+ "meant",
4097
+ "met",
4098
+ "mistaken",
4099
+ "paid",
4100
+ "proven",
4101
+ "put",
4102
+ "quit",
4103
+ "read",
4104
+ "rid",
4105
+ "ridden",
4106
+ "risen",
4107
+ "run",
4108
+ "said",
4109
+ "sat",
4110
+ "sawn",
4111
+ "seen",
4112
+ "sent",
4113
+ "set",
4114
+ "sewn",
4115
+ "shaken",
4116
+ "shed",
4117
+ "shone",
4118
+ "shot",
4119
+ "shown",
4120
+ "shrunk",
4121
+ "shut",
4122
+ "sold",
4123
+ "sought",
4124
+ "sown",
4125
+ "spent",
4126
+ "spoken",
4127
+ "spread",
4128
+ "sprung",
4129
+ "stolen",
4130
+ "stood",
4131
+ "stuck",
4132
+ "stung",
4133
+ "struck",
4134
+ "strung",
4135
+ "sung",
4136
+ "sunk",
4137
+ "swept",
4138
+ "sworn",
4139
+ "swum",
4140
+ "swung",
4141
+ "taken",
4142
+ "taught",
4143
+ "thought",
4144
+ "thrown",
4145
+ "told",
4146
+ "torn",
4147
+ "understood",
4148
+ "upset",
4149
+ "woken",
4150
+ "won",
4151
+ "worn",
4152
+ "wound",
4153
+ "woven",
4154
+ "written"
4155
+ ]);
4156
+ function isPastParticiple(word) {
4157
+ const w = word.toLowerCase();
4158
+ if (IRREGULAR_PARTICIPLES.has(w)) return true;
4159
+ return w.length > 3 && /^[a-z]+ed$/.test(w);
4160
+ }
4161
+ function splitIntoSentences(text) {
4162
+ const matches = text.match(/[^.!?]+[.!?]*/g);
4163
+ if (!matches) return [];
4164
+ return matches.map((s) => s.trim()).filter((s) => s.length > 0);
4165
+ }
4166
+ function detectPassiveVoice(text) {
4167
+ const sentences = splitIntoSentences(text);
4168
+ const analyzed = sentences.map((sentence, index) => {
4169
+ const words = sentence.match(/[a-zA-Z']+/g) ?? [];
4170
+ const matches = [];
4171
+ for (let i = 0; i < words.length; i++) {
4172
+ if (!BE_VERBS.has(words[i].toLowerCase())) continue;
4173
+ let j = i + 1;
4174
+ let adverbCount = 0;
4175
+ while (j < words.length && adverbCount < 2 && /ly$/i.test(words[j]) && !isPastParticiple(words[j])) {
4176
+ j++;
4177
+ adverbCount++;
4178
+ }
4179
+ if (j < words.length && isPastParticiple(words[j])) {
4180
+ const hasAgent = words.slice(j + 1, j + 5).some((w) => w.toLowerCase() === "by");
4181
+ matches.push({ phrase: words.slice(i, j + 1).join(" "), hasAgent });
4182
+ i = j;
4183
+ }
4184
+ }
4185
+ return { index, text: sentence, isPassive: matches.length > 0, matches };
4186
+ });
4187
+ const totalSentences = analyzed.length;
4188
+ const passiveSentences = analyzed.filter((s) => s.isPassive).length;
4189
+ const passivePercent = totalSentences > 0 ? Math.round(passiveSentences / totalSentences * 1e3) / 10 : 0;
4190
+ return { sentences: analyzed, totalSentences, passiveSentences, passivePercent };
4191
+ }
4026
4192
 
4027
4193
  // src/tools/data.ts
4028
4194
  var data_exports = {};
@@ -6378,16 +6544,16 @@ function formatValue(value, unit, decimals = 4) {
6378
6544
  return `${value.toFixed(decimals)}${unit}`;
6379
6545
  }
6380
6546
  var COMMON_SIZES = [
6381
- { px: 8, label: "8px \u2014 Extra small spacing / icon size" },
6382
- { px: 12, label: "12px \u2014 Small text / caption" },
6383
- { px: 14, label: "14px \u2014 Body small / secondary text" },
6384
- { px: 16, label: "16px \u2014 Base font size / body text" },
6385
- { px: 18, label: "18px \u2014 Body large / lead text" },
6386
- { px: 20, label: "20px \u2014 Subheading / large body" },
6387
- { px: 24, label: "24px \u2014 H4 / section title" },
6388
- { px: 32, label: "32px \u2014 H3 / card heading" },
6389
- { px: 48, label: "48px \u2014 H2 / page section heading" },
6390
- { px: 64, label: "64px \u2014 H1 / hero heading" }
6547
+ { px: 8, label: "8px: Extra small spacing / icon size" },
6548
+ { px: 12, label: "12px: Small text / caption" },
6549
+ { px: 14, label: "14px: Body small / secondary text" },
6550
+ { px: 16, label: "16px: Base font size / body text" },
6551
+ { px: 18, label: "18px: Body large / lead text" },
6552
+ { px: 20, label: "20px: Subheading / large body" },
6553
+ { px: 24, label: "24px: H4 / section title" },
6554
+ { px: 32, label: "32px: H3 / card heading" },
6555
+ { px: 48, label: "48px: H2 / page section heading" },
6556
+ { px: 64, label: "64px: H1 / hero heading" }
6391
6557
  ];
6392
6558
  function pxToViewport(px, viewportWidth = 1440, viewportHeight = 900) {
6393
6559
  const vw = parseFloat((px / viewportWidth * 100).toFixed(4));
@@ -9021,13 +9187,13 @@ function decodeJwt(token) {
9021
9187
  try {
9022
9188
  header = decodeSegment(rawHeader);
9023
9189
  } catch {
9024
- return { ok: false, error: "Failed to decode header \u2014 not valid base64url JSON" };
9190
+ return { ok: false, error: "Failed to decode header: not valid base64url JSON" };
9025
9191
  }
9026
9192
  let payload;
9027
9193
  try {
9028
9194
  payload = decodeSegment(rawPayload);
9029
9195
  } catch {
9030
- return { ok: false, error: "Failed to decode payload \u2014 not valid base64url JSON" };
9196
+ return { ok: false, error: "Failed to decode payload: not valid base64url JSON" };
9031
9197
  }
9032
9198
  const algorithm = typeof header.alg === "string" ? header.alg : "unknown";
9033
9199
  const now = Math.floor(Date.now() / 1e3);
@@ -9919,24 +10085,24 @@ var CHEATSHEET = [
9919
10085
  { pattern: "{n}", description: "Matches exactly n repetitions", example: "\\d{3} matches exactly 3 digits", category: "Quantifiers" },
9920
10086
  { pattern: "{n,}", description: "Matches n or more repetitions", example: "\\d{2,} matches 2 or more digits", category: "Quantifiers" },
9921
10087
  { pattern: "{n,m}", description: "Matches between n and m repetitions", example: "\\d{2,4} matches 2 to 4 digits", category: "Quantifiers" },
9922
- { pattern: "*?", description: "Lazy match \u2014 matches as few characters as possible", example: "<.*?> matches the shortest possible HTML tag", category: "Quantifiers" },
10088
+ { pattern: "*?", description: "Lazy match: matches as few characters as possible", example: "<.*?> matches the shortest possible HTML tag", category: "Quantifiers" },
9923
10089
  { pattern: "+?", description: "Lazy version of +", example: "a+? matches as few 'a's as possible", category: "Quantifiers" },
9924
- { pattern: "(abc)", description: "Capturing group \u2014 captures the matched substring", example: "(\\d+) captures digit sequences", category: "Groups" },
9925
- { pattern: "(?:abc)", description: "Non-capturing group \u2014 groups without capturing", example: "(?:foo|bar)baz matches 'foobaz' or 'barbaz'", category: "Groups" },
10090
+ { pattern: "(abc)", description: "Capturing group: captures the matched substring", example: "(\\d+) captures digit sequences", category: "Groups" },
10091
+ { pattern: "(?:abc)", description: "Non-capturing group: groups without capturing", example: "(?:foo|bar)baz matches 'foobaz' or 'barbaz'", category: "Groups" },
9926
10092
  { pattern: "(?<name>abc)", description: "Named capturing group", example: "(?<year>\\d{4}) captures year by name", category: "Groups" },
9927
- { pattern: "a|b", description: "Alternation \u2014 matches either a or b", example: "cat|dog matches 'cat' or 'dog'", category: "Groups" },
10093
+ { pattern: "a|b", description: "Alternation: matches either a or b", example: "cat|dog matches 'cat' or 'dog'", category: "Groups" },
9928
10094
  { pattern: "\\1", description: "Backreference to the first capturing group", example: "(\\w+) \\1 matches repeated words like 'the the'", category: "Groups" },
9929
10095
  { pattern: "\\k<name>", description: "Backreference to a named capturing group", example: "(?<word>\\w+) \\k<word> matches repeated named group", category: "Groups" },
9930
- { pattern: "(?=abc)", description: "Positive lookahead \u2014 asserts what follows matches", example: "\\d+(?= dollars) matches digits followed by ' dollars'", category: "Lookahead/Lookbehind" },
9931
- { pattern: "(?!abc)", description: "Negative lookahead \u2014 asserts what follows does not match", example: "\\d+(?! dollars) matches digits not followed by ' dollars'", category: "Lookahead/Lookbehind" },
9932
- { pattern: "(?<=abc)", description: "Positive lookbehind \u2014 asserts what precedes matches", example: "(?<=\\$)\\d+ matches digits preceded by '$'", category: "Lookahead/Lookbehind" },
9933
- { pattern: "(?<!abc)", description: "Negative lookbehind \u2014 asserts what precedes does not match", example: "(?<!\\$)\\d+ matches digits not preceded by '$'", category: "Lookahead/Lookbehind" },
9934
- { pattern: "g", description: "Global flag \u2014 finds all matches rather than stopping at the first", example: "/\\d+/g finds all numbers in a string", category: "Flags" },
9935
- { pattern: "i", description: "Case-insensitive flag \u2014 ignores letter case", example: "/hello/i matches 'Hello', 'HELLO', 'hello'", category: "Flags" },
9936
- { pattern: "m", description: "Multiline flag \u2014 ^ and $ match start/end of each line", example: "/^\\w+/m matches the first word of each line", category: "Flags" },
9937
- { pattern: "s", description: "Dotall flag \u2014 makes . match newline characters too", example: "/a.b/s matches 'a\\nb'", category: "Flags" },
9938
- { pattern: "u", description: "Unicode flag \u2014 enables full Unicode matching", example: "/\\u{1F600}/u matches a Unicode emoji", category: "Flags" },
9939
- { pattern: "y", description: "Sticky flag \u2014 matches only from the lastIndex position", example: "/\\d+/y matches digits starting at the current position", category: "Flags" },
10096
+ { pattern: "(?=abc)", description: "Positive lookahead: asserts what follows matches", example: "\\d+(?= dollars) matches digits followed by ' dollars'", category: "Lookahead/Lookbehind" },
10097
+ { pattern: "(?!abc)", description: "Negative lookahead: asserts what follows does not match", example: "\\d+(?! dollars) matches digits not followed by ' dollars'", category: "Lookahead/Lookbehind" },
10098
+ { pattern: "(?<=abc)", description: "Positive lookbehind: asserts what precedes matches", example: "(?<=\\$)\\d+ matches digits preceded by '$'", category: "Lookahead/Lookbehind" },
10099
+ { pattern: "(?<!abc)", description: "Negative lookbehind: asserts what precedes does not match", example: "(?<!\\$)\\d+ matches digits not preceded by '$'", category: "Lookahead/Lookbehind" },
10100
+ { pattern: "g", description: "Global flag: finds all matches rather than stopping at the first", example: "/\\d+/g finds all numbers in a string", category: "Flags" },
10101
+ { pattern: "i", description: "Case-insensitive flag: ignores letter case", example: "/hello/i matches 'Hello', 'HELLO', 'hello'", category: "Flags" },
10102
+ { pattern: "m", description: "Multiline flag: ^ and $ match start/end of each line", example: "/^\\w+/m matches the first word of each line", category: "Flags" },
10103
+ { pattern: "s", description: "Dotall flag: makes . match newline characters too", example: "/a.b/s matches 'a\\nb'", category: "Flags" },
10104
+ { pattern: "u", description: "Unicode flag: enables full Unicode matching", example: "/\\u{1F600}/u matches a Unicode emoji", category: "Flags" },
10105
+ { pattern: "y", description: "Sticky flag: matches only from the lastIndex position", example: "/\\d+/y matches digits starting at the current position", category: "Flags" },
9940
10106
  { pattern: "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}", description: "Matches a basic email address", example: "user@example.com", category: "Common Patterns" },
9941
10107
  { pattern: "https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w.,@?^=%&:/~+#\\-]*[\\w@?^=%&/~+#\\-])?", description: "Matches an HTTP or HTTPS URL", example: "https://www.example.com/path?query=value", category: "Common Patterns" },
9942
10108
  { pattern: "^(?:\\+1)?[-.\\s]?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}$", description: "Matches a North American phone number in various formats", example: "(555) 123-4567 or 555-123-4567", category: "Common Patterns" },
@@ -14999,7 +15165,7 @@ function getConversionWarnings(from, to) {
14999
15165
  warnings.push("Transparency will be lost if the WebP image has an alpha channel");
15000
15166
  }
15001
15167
  if (to === "image/jpeg") {
15002
- warnings.push("JPEG uses lossy compression \u2014 some quality may be reduced");
15168
+ warnings.push("JPEG uses lossy compression: some quality may be reduced");
15003
15169
  }
15004
15170
  return warnings;
15005
15171
  }
@@ -16593,6 +16759,137 @@ function summarizeForLlm(text, maxTokens = 200, strategy = "extractive") {
16593
16759
  return { summary, originalTokens: ot, summaryTokens: st, compressionRatio: Math.round(st / Math.max(1, ot) * 100) / 100, sentencesKept: picked.length, sentencesTotal: sents.length };
16594
16760
  }
16595
16761
 
16762
+ // src/tools/media.ts
16763
+ var media_exports = {};
16764
+ __export(media_exports, {
16765
+ readImageInfo: () => readImageInfo
16766
+ });
16767
+ function readU32BE(bytes, offset) {
16768
+ return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
16769
+ }
16770
+ function readI32LE(bytes, offset) {
16771
+ return bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24;
16772
+ }
16773
+ var PNG_COLOR_TYPES = {
16774
+ 0: "grayscale",
16775
+ 2: "rgb",
16776
+ 3: "palette",
16777
+ 4: "grayscale+alpha",
16778
+ 6: "rgba"
16779
+ };
16780
+ function readPng(bytes) {
16781
+ if (bytes.length < 33) return { error: "Truncated PNG file" };
16782
+ const width = readU32BE(bytes, 16);
16783
+ const height = readU32BE(bytes, 20);
16784
+ const bitDepth = bytes[24];
16785
+ const colorTypeNum = bytes[25];
16786
+ const colorType = PNG_COLOR_TYPES[colorTypeNum] ?? "unknown";
16787
+ const hasAlpha = colorTypeNum === 4 || colorTypeNum === 6;
16788
+ return { format: "png", width, height, bitDepth, colorType, hasAlpha };
16789
+ }
16790
+ function readGif(bytes) {
16791
+ if (bytes.length < 10) return { error: "Truncated GIF file" };
16792
+ const width = bytes[6] | bytes[7] << 8;
16793
+ const height = bytes[8] | bytes[9] << 8;
16794
+ return { format: "gif", width, height };
16795
+ }
16796
+ function readBmp(bytes) {
16797
+ if (bytes.length < 30) return { error: "Truncated BMP file" };
16798
+ const width = readI32LE(bytes, 18);
16799
+ const heightRaw = readI32LE(bytes, 22);
16800
+ const bitDepth = bytes[28] | bytes[29] << 8;
16801
+ return { format: "bmp", width: Math.abs(width), height: Math.abs(heightRaw), bitDepth };
16802
+ }
16803
+ function readWebp(bytes) {
16804
+ if (bytes.length < 16) return { error: "Truncated WebP file" };
16805
+ const fourCC = String.fromCharCode(bytes[12], bytes[13], bytes[14], bytes[15]);
16806
+ if (fourCC === "VP8 ") {
16807
+ if (bytes.length < 30) return { error: "Truncated WebP file" };
16808
+ const width = (bytes[26] | bytes[27] << 8) & 16383;
16809
+ const height = (bytes[28] | bytes[29] << 8) & 16383;
16810
+ return { format: "webp", width, height };
16811
+ }
16812
+ if (fourCC === "VP8L") {
16813
+ if (bytes.length < 25) return { error: "Truncated WebP file" };
16814
+ const bits = bytes[21] | bytes[22] << 8 | bytes[23] << 16 | bytes[24] << 24;
16815
+ const width = (bits & 16383) + 1;
16816
+ const height = (bits >>> 14 & 16383) + 1;
16817
+ const hasAlpha = !!(bits >>> 28 & 1);
16818
+ return { format: "webp", width, height, hasAlpha };
16819
+ }
16820
+ if (fourCC === "VP8X") {
16821
+ if (bytes.length < 30) return { error: "Truncated WebP file" };
16822
+ const flags = bytes[20];
16823
+ const hasAlpha = !!(flags & 16);
16824
+ const width = (bytes[24] | bytes[25] << 8 | bytes[26] << 16) + 1;
16825
+ const height = (bytes[27] | bytes[28] << 8 | bytes[29] << 16) + 1;
16826
+ return { format: "webp", width, height, hasAlpha };
16827
+ }
16828
+ return { error: "Unrecognized WebP chunk format" };
16829
+ }
16830
+ var JPEG_SOF_MARKERS = /* @__PURE__ */ new Set([
16831
+ 192,
16832
+ 193,
16833
+ 194,
16834
+ 195,
16835
+ 197,
16836
+ 198,
16837
+ 199,
16838
+ 201,
16839
+ 202,
16840
+ 203,
16841
+ 205,
16842
+ 206,
16843
+ 207
16844
+ ]);
16845
+ function readJpeg(bytes) {
16846
+ let offset = 2;
16847
+ while (offset < bytes.length - 1) {
16848
+ if (bytes[offset] !== 255) {
16849
+ offset++;
16850
+ continue;
16851
+ }
16852
+ const marker = bytes[offset + 1];
16853
+ if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
16854
+ offset += 2;
16855
+ continue;
16856
+ }
16857
+ if (marker === 217) break;
16858
+ if (offset + 3 >= bytes.length) break;
16859
+ const segmentLength = bytes[offset + 2] << 8 | bytes[offset + 3];
16860
+ if (JPEG_SOF_MARKERS.has(marker)) {
16861
+ if (offset + 9 >= bytes.length) return { error: "Truncated JPEG SOF segment" };
16862
+ const bitDepth = bytes[offset + 4];
16863
+ const height = bytes[offset + 5] << 8 | bytes[offset + 6];
16864
+ const width = bytes[offset + 7] << 8 | bytes[offset + 8];
16865
+ const components = bytes[offset + 9];
16866
+ const colorType = components === 1 ? "grayscale" : components === 3 ? "rgb" : components === 4 ? "cmyk" : "unknown";
16867
+ return { format: "jpeg", width, height, bitDepth, colorType };
16868
+ }
16869
+ offset += 2 + segmentLength;
16870
+ }
16871
+ return { error: "No SOF marker found in JPEG (file may be corrupt)" };
16872
+ }
16873
+ function readImageInfo(bytes) {
16874
+ if (bytes.length < 10) return { error: "File too small to determine format" };
16875
+ if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) {
16876
+ return readPng(bytes);
16877
+ }
16878
+ if (bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) {
16879
+ return readGif(bytes);
16880
+ }
16881
+ if (bytes[0] === 66 && bytes[1] === 77) {
16882
+ return readBmp(bytes);
16883
+ }
16884
+ if (bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
16885
+ return readWebp(bytes);
16886
+ }
16887
+ if (bytes[0] === 255 && bytes[1] === 216) {
16888
+ return readJpeg(bytes);
16889
+ }
16890
+ return { error: "Unrecognized image format. Supported formats: PNG, JPEG, GIF, WebP, BMP" };
16891
+ }
16892
+
16596
16893
  // src/index.ts
16597
16894
  var version = "0.1.0";
16598
16895
 
@@ -16606,6 +16903,7 @@ exports.encoding = encoding_exports;
16606
16903
  exports.generators = generators_exports;
16607
16904
  exports.hashing = hashing_exports;
16608
16905
  exports.json = json_exports;
16906
+ exports.media = media_exports;
16609
16907
  exports.misc = misc_exports;
16610
16908
  exports.network = network_exports;
16611
16909
  exports.text = text_exports;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { j as json } from './json-BjSoIS1h.cjs';
2
2
  export { e as encoding } from './encoding-7gmq-vkV.cjs';
3
3
  export { h as hashing } from './hashing-CnetQFD_.cjs';
4
- export { t as text } from './text-DqAjPtQ0.cjs';
4
+ export { t as text } from './text-CI7JAl7F.cjs';
5
5
  export { d as data } from './data-rMjWNiOJ.cjs';
6
6
  export { g as generators } from './generators-BGtRGpJZ.cjs';
7
7
  export { t as time } from './time-DbT8fjaF.cjs';
@@ -13,6 +13,7 @@ export { c as color } from './color-tPwZCr9H.cjs';
13
13
  export { c as css } from './css-Cf7AMGM-.cjs';
14
14
  export { m as misc } from './misc-CA3N198T.cjs';
15
15
  export { a as ai_agent } from './ai_agent-CcpkV2DR.cjs';
16
+ export { m as media } from './media-DF2cx3pK.cjs';
16
17
 
17
18
  declare const version = "0.1.0";
18
19
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { j as json } from './json-BjSoIS1h.js';
2
2
  export { e as encoding } from './encoding-7gmq-vkV.js';
3
3
  export { h as hashing } from './hashing-CnetQFD_.js';
4
- export { t as text } from './text-DqAjPtQ0.js';
4
+ export { t as text } from './text-CI7JAl7F.js';
5
5
  export { d as data } from './data-rMjWNiOJ.js';
6
6
  export { g as generators } from './generators-BGtRGpJZ.js';
7
7
  export { t as time } from './time-DbT8fjaF.js';
@@ -13,6 +13,7 @@ export { c as color } from './color-tPwZCr9H.js';
13
13
  export { c as css } from './css-Cf7AMGM-.js';
14
14
  export { m as misc } from './misc-CA3N198T.js';
15
15
  export { a as ai_agent } from './ai_agent-CcpkV2DR.js';
16
+ export { m as media } from './media-DF2cx3pK.js';
16
17
 
17
18
  declare const version = "0.1.0";
18
19
 
package/dist/index.js CHANGED
@@ -1,15 +1,16 @@
1
- export { units_exports as units } from './chunk-XST6X3HT.js';
1
+ export { media_exports as media } from './chunk-N7C52YGL.js';
2
+ export { units_exports as units } from './chunk-QJE743LY.js';
2
3
  export { network_exports as network } from './chunk-3BAHSW4C.js';
3
- export { api_exports as api } from './chunk-W4UBLYFU.js';
4
- export { code_exports as code } from './chunk-NSOARQCM.js';
4
+ export { api_exports as api } from './chunk-HFRTZE7T.js';
5
+ export { code_exports as code } from './chunk-V5S6OJ4A.js';
5
6
  export { color_exports as color } from './chunk-BPVAB4P2.js';
6
7
  export { css_exports as css } from './chunk-6YPV2AB5.js';
7
- export { misc_exports as misc } from './chunk-OKSWDVOM.js';
8
+ export { misc_exports as misc } from './chunk-GX7H6TAX.js';
8
9
  export { ai_agent_exports as ai_agent } from './chunk-M35VJETW.js';
9
10
  export { json_exports as json } from './chunk-TSAGO3XP.js';
10
- export { encoding_exports as encoding } from './chunk-ROTPLW7T.js';
11
+ export { encoding_exports as encoding } from './chunk-IPR7FSX4.js';
11
12
  export { hashing_exports as hashing } from './chunk-FL53T24A.js';
12
- export { text_exports as text } from './chunk-XXYZLLHI.js';
13
+ export { text_exports as text } from './chunk-YBBYFAOV.js';
13
14
  export { data_exports as data } from './chunk-UC656APA.js';
14
15
  export { generators_exports as generators } from './chunk-2CJSLYWI.js';
15
16
  export { time_exports as time } from './chunk-ZPQZEIXP.js';