@utilix-tech/sdk 0.79.0 → 0.81.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 +24 -4
- package/dist/{chunk-XT2BQWXT.js → chunk-FPFA4ZHC.js} +393 -1
- package/dist/{chunk-34C6GXCC.js → chunk-WUOZHCIC.js} +217 -1
- package/dist/{code-46xO9xFf.d.cts → code-B8yHwP3m.d.cts} +83 -2
- package/dist/{code-46xO9xFf.d.ts → code-B8yHwP3m.d.ts} +83 -2
- package/dist/index.cjs +608 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{json-CaiYsGDQ.d.cts → json-Ca6gZCNB.d.cts} +45 -2
- package/dist/{json-CaiYsGDQ.d.ts → json-Ca6gZCNB.d.ts} +45 -2
- package/dist/tools/code.cjs +392 -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/json.cjs +216 -0
- package/dist/tools/json.d.cts +1 -1
- package/dist/tools/json.d.ts +1 -1
- package/dist/tools/json.js +1 -1
- 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.81.0
|
|
6
|
+
- Add `validateFenceLanguageTags` (markdown-fence-lang-validator): scan a Markdown document's fenced code blocks and flag a missing, unknown, or inconsistently-cased language tag against a curated list of common syntax-highlighter identifiers.
|
|
7
|
+
- Add `countSqlPlaceholders` (sql-placeholder-counter): count positional (`?`, `$1`) and named (`:name`, `@name`) parameter placeholders in a SQL query, flagging mixed styles and numbered-sequence gaps or duplicates.
|
|
8
|
+
|
|
9
|
+
## 0.80.0
|
|
10
|
+
- Add `diffJsonPatch`, `applyJsonPatch`, `generateJsonPatch` (json-patch): diff two JSON documents into an RFC 6902 JSON Patch operation list (add/remove/replace/move/copy/test), or apply a patch to a target document.
|
|
11
|
+
- Add `parseConnectionString` (connection-string-parser): parse a database connection URI (postgres, mysql, mongodb, redis, amqp, and similar) into its scheme, credentials, hosts, database, and query parameters.
|
|
12
|
+
|
|
5
13
|
## 0.79.0
|
|
6
14
|
- Add `calculateRealRateOfReturn` (real-rate-of-return-calculator): apply the Fisher equation to solve for whichever of the nominal rate, inflation rate, or inflation-adjusted real rate is missing, given exactly two of the three.
|
|
7
15
|
- Add `calculateRetryBackoffSchedule` (retry-backoff-calculator): compute the full sequence of delays an exponential-backoff retry policy would actually produce, optionally capped and with full/equal jitter ranges, plus the total best-case and worst-case wait across all retries.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**715 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)
|
|
@@ -66,7 +66,8 @@ const { formatJson } = require("@utilix-tech/sdk/json");
|
|
|
66
66
|
|
|
67
67
|
```ts
|
|
68
68
|
import { formatJson, minifyJson, diffJson, jsonToTypescript, jsonSchemaToTypescript, validateJson,
|
|
69
|
-
evaluateJsonPath, resolveJsonPointer, applyJsonMergePatch,
|
|
69
|
+
evaluateJsonPath, resolveJsonPointer, applyJsonMergePatch, diffJsonPatch, applyJsonPatch,
|
|
70
|
+
jsonToCsv, yamlToJson, jsonToYaml, getJsonStats } from "@utilix-tech/sdk/json";
|
|
70
71
|
|
|
71
72
|
// Format with 2-space indent
|
|
72
73
|
formatJson('{"name":"alice","age":30}', { indent: 2 });
|
|
@@ -91,6 +92,12 @@ resolveJsonPointer('{"users":[{"name":"Alice"}]}', "/users/0/name");
|
|
|
91
92
|
applyJsonMergePatch('{"a":"b","c":{"d":"e","f":"g"}}', '{"a":"z","c":{"f":null}}');
|
|
92
93
|
// { result: { a: "z", c: { d: "e" } } }
|
|
93
94
|
|
|
95
|
+
// Diff two documents into an RFC 6902 JSON Patch, or apply one
|
|
96
|
+
diffJsonPatch({ a: 1 }, { a: 2 });
|
|
97
|
+
// [{ op: "replace", path: "/a", value: 2 }]
|
|
98
|
+
applyJsonPatch({ foo: "bar" }, [{ op: "add", path: "/baz", value: "qux" }]);
|
|
99
|
+
// { result: { foo: "bar", baz: "qux" } }
|
|
100
|
+
|
|
94
101
|
// Convert JSON to CSV
|
|
95
102
|
jsonToCsv('[{"a":1,"b":2}]');
|
|
96
103
|
|
|
@@ -773,7 +780,8 @@ generateCspHeader({ "default-src": ["'self'"], "script-src": ["'self'", "cdn.exa
|
|
|
773
780
|
import { formatSql, minifySql, testRegex, formatHtml, formatGql,
|
|
774
781
|
detectDialect, splitStatements, lookupMime, parseGithubUrl,
|
|
775
782
|
detectRedos, analyzeRegexGroups, testGitignorePatterns, validateEditorConfig,
|
|
776
|
-
validateTsconfig, validatePackageExports
|
|
783
|
+
validateTsconfig, validatePackageExports, parseConnectionString,
|
|
784
|
+
validateFenceLanguageTags, countSqlPlaceholders } from "@utilix-tech/sdk/code";
|
|
777
785
|
|
|
778
786
|
// SQL
|
|
779
787
|
formatSql("SELECT id,name FROM users WHERE active=1 ORDER BY name");
|
|
@@ -806,6 +814,18 @@ lookupMime("image/jpeg"); // { kind: "mime", matches: [{ extension: "jpg", ...
|
|
|
806
814
|
parseGithubUrl("https://github.com/facebook/react/pull/1234");
|
|
807
815
|
// { owner: "facebook", repo: "react", type: "pull", number: 1234 }
|
|
808
816
|
|
|
817
|
+
// Database connection string parsing
|
|
818
|
+
parseConnectionString("postgres://user:pass@localhost:5432/mydb?sslmode=require");
|
|
819
|
+
// { scheme: "postgres", user: "user", password: "pass", hosts: [{ host: "localhost", port: 5432 }], database: "mydb", params: { sslmode: "require" } }
|
|
820
|
+
|
|
821
|
+
// Markdown code fence language tag validation
|
|
822
|
+
validateFenceLanguageTags("```JS\nconsole.log(1)\n```\n");
|
|
823
|
+
// { totalFences: 1, issues: [{ line: 1, tag: "JS", issue: "inconsistent-case", suggestion: "js" }] }
|
|
824
|
+
|
|
825
|
+
// SQL query parameter placeholder counting
|
|
826
|
+
countSqlPlaceholders("SELECT * FROM users WHERE id = ? AND age > $1");
|
|
827
|
+
// { placeholders: [...], counts: { anonymous: 1, numbered: 1, "named-colon": 0, "named-at": 0 }, mixedStyles: true, numberedGaps: [], numberedDuplicates: [] }
|
|
828
|
+
|
|
809
829
|
// Regex ReDoS (catastrophic-backtracking) detection
|
|
810
830
|
detectRedos("(a+)+");
|
|
811
831
|
// { risk: "high", safe: false, findings: [{ type: "nested-quantifier", ... }] }
|
|
@@ -1026,7 +1046,7 @@ readMidiInfo(new Uint8Array(midiBytes));
|
|
|
1026
1046
|
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN/VIN/ISIN 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, debt-to-income ratio calculator, freelancer hourly rate calculator, debt snowball/avalanche payoff planner, tax-equivalent yield calculator, mortgage discount points break-even calculator, loan prepayment penalty calculator, data transfer time / required bandwidth estimator, real rate of return (Fisher equation) calculator |
|
|
1027
1047
|
| `@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, Content-Disposition header builder/parser, X-Content-Type-Options header builder/risk assessor, sitemap.xml validator, sitemap index splitter, Prefer header builder/parser (RFC 7240), Retry-After header builder/parser (RFC 9110), Priority header builder/parser (RFC 9218), WebSocket close code reference/lookup, Strict-Transport-Security (HSTS) header builder/parser, X-Robots-Tag header builder/parser, WebSocket frame opcode reference/lookup, robots meta tag builder/parser, Cookie header byte-size budget calculator |
|
|
1028
1048
|
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header, TOTP/HOTP code generator, webhook HMAC signature verifier |
|
|
1029
|
-
| `@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, package.json exports field validator, package.json dependency range auditor, regex capture group/backreference visualizer, SVG sprite symbol extractor, ARIA role & attribute validator |
|
|
1049
|
+
| `@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, package.json exports field validator, package.json dependency range auditor, regex capture group/backreference visualizer, SVG sprite symbol extractor, ARIA role & attribute validator, database connection string parser, Markdown code fence language tag validator, SQL query parameter placeholder counter |
|
|
1030
1050
|
| `@utilix-tech/sdk/color` | Hex/RGB/HSL/HSV/CMYK convert, palette generation, contrast check |
|
|
1031
1051
|
| `@utilix-tech/sdk/css` | CSS gradient, box-shadow, border-radius, keyframe animation generators |
|
|
1032
1052
|
| `@utilix-tech/sdk/misc` | SVG optimize/sanitize, file size format, Unicode inspector |
|
|
@@ -7,6 +7,7 @@ __export(code_exports, {
|
|
|
7
7
|
ALL_FLAGS: () => ALL_FLAGS,
|
|
8
8
|
CHEATSHEET: () => CHEATSHEET,
|
|
9
9
|
DEFAULT_COMMIT_TYPES: () => DEFAULT_COMMIT_TYPES,
|
|
10
|
+
KNOWN_LANGUAGE_TAGS: () => KNOWN_LANGUAGE_TAGS,
|
|
10
11
|
MIME_TABLE: () => MIME_TABLE,
|
|
11
12
|
OPERATIONS: () => OPERATIONS,
|
|
12
13
|
SQL_DEFAULT_OPTIONS: () => SQL_DEFAULT_OPTIONS,
|
|
@@ -19,6 +20,7 @@ __export(code_exports, {
|
|
|
19
20
|
collapseJsWhitespace: () => collapseJsWhitespace,
|
|
20
21
|
countProperties: () => countProperties,
|
|
21
22
|
countRules: () => countRules,
|
|
23
|
+
countSqlPlaceholders: () => countSqlPlaceholders,
|
|
22
24
|
detectDialect: () => detectDialect,
|
|
23
25
|
detectOperationType: () => detectOperationType,
|
|
24
26
|
detectRedos: () => detectRedos,
|
|
@@ -44,6 +46,7 @@ __export(code_exports, {
|
|
|
44
46
|
minifySql: () => minifySql,
|
|
45
47
|
normalizeRef: () => normalizeRef,
|
|
46
48
|
parseCommitTrailers: () => parseCommitTrailers,
|
|
49
|
+
parseConnectionString: () => parseConnectionString,
|
|
47
50
|
parseDockerImage: () => parseDockerImage,
|
|
48
51
|
parseEnv: () => parseEnv,
|
|
49
52
|
parseGitCommand: () => parseGitCommand,
|
|
@@ -63,6 +66,7 @@ __export(code_exports, {
|
|
|
63
66
|
validateAria: () => validateAria,
|
|
64
67
|
validateEditorConfig: () => validateEditorConfig,
|
|
65
68
|
validateEnvKey: () => validateEnvKey,
|
|
69
|
+
validateFenceLanguageTags: () => validateFenceLanguageTags,
|
|
66
70
|
validatePackageExports: () => validatePackageExports,
|
|
67
71
|
validateTsconfig: () => validateTsconfig
|
|
68
72
|
});
|
|
@@ -3876,5 +3880,393 @@ function validateAria(html) {
|
|
|
3876
3880
|
valid: issues.every((i) => i.severity !== "error")
|
|
3877
3881
|
};
|
|
3878
3882
|
}
|
|
3883
|
+
var CONNECTION_STRING_RE = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/(?:([^@/?#]*)@)?([^/?#]*)(?:\/([^?#]*))?(?:\?([^#]*))?$/;
|
|
3884
|
+
function _parseConnectionHost(segment) {
|
|
3885
|
+
const ipv6Match = segment.match(/^\[([^\]]+)\](?::(\d+))?$/);
|
|
3886
|
+
if (ipv6Match) {
|
|
3887
|
+
return { host: ipv6Match[1], port: ipv6Match[2] ? parseInt(ipv6Match[2], 10) : null };
|
|
3888
|
+
}
|
|
3889
|
+
const lastColon = segment.lastIndexOf(":");
|
|
3890
|
+
if (lastColon === -1) return { host: segment, port: null };
|
|
3891
|
+
const portPart = segment.slice(lastColon + 1);
|
|
3892
|
+
if (!/^\d+$/.test(portPart)) return { host: segment, port: null };
|
|
3893
|
+
return { host: segment.slice(0, lastColon), port: parseInt(portPart, 10) };
|
|
3894
|
+
}
|
|
3895
|
+
function parseConnectionString(input) {
|
|
3896
|
+
if (!input || typeof input !== "string" || !input.trim()) {
|
|
3897
|
+
return { error: "Connection string is empty" };
|
|
3898
|
+
}
|
|
3899
|
+
const trimmed = input.trim();
|
|
3900
|
+
const match = trimmed.match(CONNECTION_STRING_RE);
|
|
3901
|
+
if (!match) {
|
|
3902
|
+
return { error: "Not a valid scheme://[user[:password]@]host[,host2][/database][?params] connection string" };
|
|
3903
|
+
}
|
|
3904
|
+
const [, scheme, userinfo, hostPart, databasePart, queryPart] = match;
|
|
3905
|
+
let user = null;
|
|
3906
|
+
let password = null;
|
|
3907
|
+
if (userinfo) {
|
|
3908
|
+
const sepIndex = userinfo.indexOf(":");
|
|
3909
|
+
if (sepIndex === -1) {
|
|
3910
|
+
user = decodeURIComponent(userinfo);
|
|
3911
|
+
} else {
|
|
3912
|
+
user = decodeURIComponent(userinfo.slice(0, sepIndex));
|
|
3913
|
+
password = decodeURIComponent(userinfo.slice(sepIndex + 1));
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
const hosts = hostPart ? hostPart.split(",").filter(Boolean).map(_parseConnectionHost) : [];
|
|
3917
|
+
const database = databasePart ? decodeURIComponent(databasePart) : null;
|
|
3918
|
+
const params = {};
|
|
3919
|
+
if (queryPart) {
|
|
3920
|
+
for (const pair of queryPart.split("&")) {
|
|
3921
|
+
if (!pair) continue;
|
|
3922
|
+
const eqIndex = pair.indexOf("=");
|
|
3923
|
+
const key = eqIndex === -1 ? pair : pair.slice(0, eqIndex);
|
|
3924
|
+
const value = eqIndex === -1 ? "" : pair.slice(eqIndex + 1);
|
|
3925
|
+
params[decodeURIComponent(key)] = decodeURIComponent(value);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
return { scheme, user, password, hosts, database, params };
|
|
3929
|
+
}
|
|
3930
|
+
var KNOWN_LANGUAGE_TAGS = /* @__PURE__ */ new Set([
|
|
3931
|
+
"js",
|
|
3932
|
+
"jsx",
|
|
3933
|
+
"mjs",
|
|
3934
|
+
"cjs",
|
|
3935
|
+
"javascript",
|
|
3936
|
+
"ts",
|
|
3937
|
+
"tsx",
|
|
3938
|
+
"typescript",
|
|
3939
|
+
"json",
|
|
3940
|
+
"json5",
|
|
3941
|
+
"jsonc",
|
|
3942
|
+
"jsonl",
|
|
3943
|
+
"ndjson",
|
|
3944
|
+
"yaml",
|
|
3945
|
+
"yml",
|
|
3946
|
+
"toml",
|
|
3947
|
+
"ini",
|
|
3948
|
+
"cfg",
|
|
3949
|
+
"conf",
|
|
3950
|
+
"properties",
|
|
3951
|
+
"env",
|
|
3952
|
+
"dotenv",
|
|
3953
|
+
"html",
|
|
3954
|
+
"htm",
|
|
3955
|
+
"xml",
|
|
3956
|
+
"svg",
|
|
3957
|
+
"xhtml",
|
|
3958
|
+
"css",
|
|
3959
|
+
"scss",
|
|
3960
|
+
"sass",
|
|
3961
|
+
"less",
|
|
3962
|
+
"stylus",
|
|
3963
|
+
"styl",
|
|
3964
|
+
"markdown",
|
|
3965
|
+
"md",
|
|
3966
|
+
"mdx",
|
|
3967
|
+
"bash",
|
|
3968
|
+
"sh",
|
|
3969
|
+
"shell",
|
|
3970
|
+
"zsh",
|
|
3971
|
+
"fish",
|
|
3972
|
+
"console",
|
|
3973
|
+
"powershell",
|
|
3974
|
+
"ps1",
|
|
3975
|
+
"bat",
|
|
3976
|
+
"cmd",
|
|
3977
|
+
"python",
|
|
3978
|
+
"py",
|
|
3979
|
+
"py3",
|
|
3980
|
+
"ipynb",
|
|
3981
|
+
"ruby",
|
|
3982
|
+
"rb",
|
|
3983
|
+
"erb",
|
|
3984
|
+
"php",
|
|
3985
|
+
"java",
|
|
3986
|
+
"kotlin",
|
|
3987
|
+
"kt",
|
|
3988
|
+
"kts",
|
|
3989
|
+
"groovy",
|
|
3990
|
+
"gradle",
|
|
3991
|
+
"swift",
|
|
3992
|
+
"objectivec",
|
|
3993
|
+
"objc",
|
|
3994
|
+
"go",
|
|
3995
|
+
"golang",
|
|
3996
|
+
"rust",
|
|
3997
|
+
"rs",
|
|
3998
|
+
"c",
|
|
3999
|
+
"h",
|
|
4000
|
+
"cpp",
|
|
4001
|
+
"cc",
|
|
4002
|
+
"cxx",
|
|
4003
|
+
"hpp",
|
|
4004
|
+
"c++",
|
|
4005
|
+
"csharp",
|
|
4006
|
+
"cs",
|
|
4007
|
+
"fsharp",
|
|
4008
|
+
"fs",
|
|
4009
|
+
"perl",
|
|
4010
|
+
"pl",
|
|
4011
|
+
"lua",
|
|
4012
|
+
"r",
|
|
4013
|
+
"matlab",
|
|
4014
|
+
"m",
|
|
4015
|
+
"scala",
|
|
4016
|
+
"nim",
|
|
4017
|
+
"zig",
|
|
4018
|
+
"julia",
|
|
4019
|
+
"jl",
|
|
4020
|
+
"haskell",
|
|
4021
|
+
"hs",
|
|
4022
|
+
"elixir",
|
|
4023
|
+
"ex",
|
|
4024
|
+
"exs",
|
|
4025
|
+
"erlang",
|
|
4026
|
+
"erl",
|
|
4027
|
+
"clojure",
|
|
4028
|
+
"clj",
|
|
4029
|
+
"cljs",
|
|
4030
|
+
"dart",
|
|
4031
|
+
"ocaml",
|
|
4032
|
+
"ml",
|
|
4033
|
+
"sql",
|
|
4034
|
+
"mysql",
|
|
4035
|
+
"postgresql",
|
|
4036
|
+
"plsql",
|
|
4037
|
+
"sqlite",
|
|
4038
|
+
"graphql",
|
|
4039
|
+
"gql",
|
|
4040
|
+
"dockerfile",
|
|
4041
|
+
"docker",
|
|
4042
|
+
"makefile",
|
|
4043
|
+
"make",
|
|
4044
|
+
"cmake",
|
|
4045
|
+
"nginx",
|
|
4046
|
+
"apache",
|
|
4047
|
+
"diff",
|
|
4048
|
+
"patch",
|
|
4049
|
+
"git",
|
|
4050
|
+
"http",
|
|
4051
|
+
"proto",
|
|
4052
|
+
"protobuf",
|
|
4053
|
+
"csv",
|
|
4054
|
+
"tsv",
|
|
4055
|
+
"vim",
|
|
4056
|
+
"viml",
|
|
4057
|
+
"tex",
|
|
4058
|
+
"latex",
|
|
4059
|
+
"bibtex",
|
|
4060
|
+
"plaintext",
|
|
4061
|
+
"text",
|
|
4062
|
+
"txt",
|
|
4063
|
+
"nohighlight",
|
|
4064
|
+
"none",
|
|
4065
|
+
"asciidoc",
|
|
4066
|
+
"adoc",
|
|
4067
|
+
"rst",
|
|
4068
|
+
"vue",
|
|
4069
|
+
"svelte",
|
|
4070
|
+
"astro",
|
|
4071
|
+
"wasm",
|
|
4072
|
+
"wat",
|
|
4073
|
+
"handlebars",
|
|
4074
|
+
"hbs",
|
|
4075
|
+
"pug",
|
|
4076
|
+
"jade",
|
|
4077
|
+
"coffee",
|
|
4078
|
+
"coffeescript",
|
|
4079
|
+
"actionscript",
|
|
4080
|
+
"terraform",
|
|
4081
|
+
"tf",
|
|
4082
|
+
"hcl",
|
|
4083
|
+
"puppet",
|
|
4084
|
+
"ansible"
|
|
4085
|
+
]);
|
|
4086
|
+
function _parseFenceLine(line) {
|
|
4087
|
+
const match = line.match(/^( {0,3})(`{3,}|~{3,})(.*)$/);
|
|
4088
|
+
if (!match) return null;
|
|
4089
|
+
const [, indent, marker, rest] = match;
|
|
4090
|
+
const char = marker[0];
|
|
4091
|
+
if (char === "`" && rest.includes("`")) return null;
|
|
4092
|
+
return { indent: indent.length, char, length: marker.length, infoString: rest.trim() };
|
|
4093
|
+
}
|
|
4094
|
+
function _isClosingFence(line, fenceChar, fenceLength) {
|
|
4095
|
+
const match = line.match(/^ {0,3}(`+|~+)\s*$/);
|
|
4096
|
+
if (!match) return false;
|
|
4097
|
+
const marker = match[1];
|
|
4098
|
+
return marker[0] === fenceChar && marker.length >= fenceLength;
|
|
4099
|
+
}
|
|
4100
|
+
function validateFenceLanguageTags(markdown) {
|
|
4101
|
+
const lines = markdown.split("\n");
|
|
4102
|
+
const issues = [];
|
|
4103
|
+
let totalFences = 0;
|
|
4104
|
+
let open = null;
|
|
4105
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4106
|
+
const lineNumber = i + 1;
|
|
4107
|
+
const line = lines[i];
|
|
4108
|
+
if (open) {
|
|
4109
|
+
if (_isClosingFence(line, open.char, open.length)) open = null;
|
|
4110
|
+
continue;
|
|
4111
|
+
}
|
|
4112
|
+
const fence = _parseFenceLine(line);
|
|
4113
|
+
if (!fence) continue;
|
|
4114
|
+
totalFences++;
|
|
4115
|
+
const tag = fence.infoString.split(/\s+/)[0] ?? "";
|
|
4116
|
+
open = { char: fence.char, length: fence.length };
|
|
4117
|
+
if (tag === "") {
|
|
4118
|
+
issues.push({ line: lineNumber, tag, issue: "missing" });
|
|
4119
|
+
continue;
|
|
4120
|
+
}
|
|
4121
|
+
const lower = tag.toLowerCase();
|
|
4122
|
+
if (!KNOWN_LANGUAGE_TAGS.has(lower)) {
|
|
4123
|
+
issues.push({ line: lineNumber, tag, issue: "unknown" });
|
|
4124
|
+
continue;
|
|
4125
|
+
}
|
|
4126
|
+
if (tag !== lower) {
|
|
4127
|
+
issues.push({ line: lineNumber, tag, issue: "inconsistent-case", suggestion: lower });
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
return { totalFences, issues };
|
|
4131
|
+
}
|
|
4132
|
+
var _IDENT_START = /[A-Za-z_]/;
|
|
4133
|
+
var _IDENT_CHAR = /[A-Za-z0-9_]/;
|
|
4134
|
+
function _readIdentifier(sql, start) {
|
|
4135
|
+
let end = start;
|
|
4136
|
+
while (end < sql.length && _IDENT_CHAR.test(sql[end])) end++;
|
|
4137
|
+
return sql.slice(start, end);
|
|
4138
|
+
}
|
|
4139
|
+
function countSqlPlaceholders(sql) {
|
|
4140
|
+
const placeholders = [];
|
|
4141
|
+
let state = "normal";
|
|
4142
|
+
let i = 0;
|
|
4143
|
+
while (i < sql.length) {
|
|
4144
|
+
const ch = sql[i];
|
|
4145
|
+
const next = sql[i + 1];
|
|
4146
|
+
if (state === "single") {
|
|
4147
|
+
if (ch === "'" && next === "'") {
|
|
4148
|
+
i += 2;
|
|
4149
|
+
continue;
|
|
4150
|
+
}
|
|
4151
|
+
if (ch === "'") {
|
|
4152
|
+
state = "normal";
|
|
4153
|
+
i++;
|
|
4154
|
+
continue;
|
|
4155
|
+
}
|
|
4156
|
+
i++;
|
|
4157
|
+
continue;
|
|
4158
|
+
}
|
|
4159
|
+
if (state === "double") {
|
|
4160
|
+
if (ch === '"' && next === '"') {
|
|
4161
|
+
i += 2;
|
|
4162
|
+
continue;
|
|
4163
|
+
}
|
|
4164
|
+
if (ch === '"') {
|
|
4165
|
+
state = "normal";
|
|
4166
|
+
i++;
|
|
4167
|
+
continue;
|
|
4168
|
+
}
|
|
4169
|
+
i++;
|
|
4170
|
+
continue;
|
|
4171
|
+
}
|
|
4172
|
+
if (state === "line-comment") {
|
|
4173
|
+
if (ch === "\n") state = "normal";
|
|
4174
|
+
i++;
|
|
4175
|
+
continue;
|
|
4176
|
+
}
|
|
4177
|
+
if (state === "block-comment") {
|
|
4178
|
+
if (ch === "*" && next === "/") {
|
|
4179
|
+
state = "normal";
|
|
4180
|
+
i += 2;
|
|
4181
|
+
continue;
|
|
4182
|
+
}
|
|
4183
|
+
i++;
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
if (ch === "'") {
|
|
4187
|
+
state = "single";
|
|
4188
|
+
i++;
|
|
4189
|
+
continue;
|
|
4190
|
+
}
|
|
4191
|
+
if (ch === '"') {
|
|
4192
|
+
state = "double";
|
|
4193
|
+
i++;
|
|
4194
|
+
continue;
|
|
4195
|
+
}
|
|
4196
|
+
if (ch === "-" && next === "-") {
|
|
4197
|
+
state = "line-comment";
|
|
4198
|
+
i += 2;
|
|
4199
|
+
continue;
|
|
4200
|
+
}
|
|
4201
|
+
if (ch === "/" && next === "*") {
|
|
4202
|
+
state = "block-comment";
|
|
4203
|
+
i += 2;
|
|
4204
|
+
continue;
|
|
4205
|
+
}
|
|
4206
|
+
if (ch === "?") {
|
|
4207
|
+
placeholders.push({ style: "anonymous", raw: "?", index: i });
|
|
4208
|
+
i++;
|
|
4209
|
+
continue;
|
|
4210
|
+
}
|
|
4211
|
+
if (ch === "$" && /[0-9]/.test(next ?? "")) {
|
|
4212
|
+
let end = i + 1;
|
|
4213
|
+
while (end < sql.length && /[0-9]/.test(sql[end])) end++;
|
|
4214
|
+
const raw = sql.slice(i, end);
|
|
4215
|
+
placeholders.push({ style: "numbered", raw, index: i, number: parseInt(raw.slice(1), 10) });
|
|
4216
|
+
i = end;
|
|
4217
|
+
continue;
|
|
4218
|
+
}
|
|
4219
|
+
if (ch === ":") {
|
|
4220
|
+
if (next === ":") {
|
|
4221
|
+
i += 2;
|
|
4222
|
+
continue;
|
|
4223
|
+
}
|
|
4224
|
+
if (next && _IDENT_START.test(next)) {
|
|
4225
|
+
const name = _readIdentifier(sql, i + 1);
|
|
4226
|
+
placeholders.push({ style: "named-colon", raw: `:${name}`, index: i, name });
|
|
4227
|
+
i += 1 + name.length;
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
i++;
|
|
4231
|
+
continue;
|
|
4232
|
+
}
|
|
4233
|
+
if (ch === "@") {
|
|
4234
|
+
if (next === "@") {
|
|
4235
|
+
i += 2;
|
|
4236
|
+
continue;
|
|
4237
|
+
}
|
|
4238
|
+
if (next && _IDENT_START.test(next)) {
|
|
4239
|
+
const name = _readIdentifier(sql, i + 1);
|
|
4240
|
+
placeholders.push({ style: "named-at", raw: `@${name}`, index: i, name });
|
|
4241
|
+
i += 1 + name.length;
|
|
4242
|
+
continue;
|
|
4243
|
+
}
|
|
4244
|
+
i++;
|
|
4245
|
+
continue;
|
|
4246
|
+
}
|
|
4247
|
+
i++;
|
|
4248
|
+
}
|
|
4249
|
+
const counts = { anonymous: 0, numbered: 0, "named-colon": 0, "named-at": 0 };
|
|
4250
|
+
for (const p of placeholders) counts[p.style]++;
|
|
4251
|
+
const stylesUsed = ["anonymous", "numbered", "named-colon", "named-at"].filter((s) => counts[s] > 0);
|
|
4252
|
+
const numbers = placeholders.filter((p) => p.style === "numbered").map((p) => p.number);
|
|
4253
|
+
const maxNumber = numbers.length > 0 ? Math.max(...numbers) : 0;
|
|
4254
|
+
const seen = new Set(numbers);
|
|
4255
|
+
const numberedGaps = [];
|
|
4256
|
+
for (let n = 1; n < maxNumber; n++) {
|
|
4257
|
+
if (!seen.has(n)) numberedGaps.push(n);
|
|
4258
|
+
}
|
|
4259
|
+
const countedMap = /* @__PURE__ */ new Map();
|
|
4260
|
+
for (const n of numbers) countedMap.set(n, (countedMap.get(n) ?? 0) + 1);
|
|
4261
|
+
const numberedDuplicates = [...countedMap.entries()].filter(([, c]) => c > 1).map(([n]) => n).sort((a, b) => a - b);
|
|
4262
|
+
return {
|
|
4263
|
+
placeholders,
|
|
4264
|
+
counts,
|
|
4265
|
+
stylesUsed,
|
|
4266
|
+
mixedStyles: stylesUsed.length > 1,
|
|
4267
|
+
numberedGaps,
|
|
4268
|
+
numberedDuplicates
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
3879
4271
|
|
|
3880
|
-
export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, analyzeRegexGroups, auditDependencyRanges, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, extractMarkdownFootnotes, extractSvgSpriteSymbols, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lintConventionalCommit, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseCommitTrailers, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testGitignorePatterns, testPattern, testRegex, validateAria, validateEditorConfig, validateEnvKey, validatePackageExports, validateTsconfig };
|
|
4272
|
+
export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, KNOWN_LANGUAGE_TAGS, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, analyzeRegexGroups, auditDependencyRanges, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, countSqlPlaceholders, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, extractMarkdownFootnotes, extractSvgSpriteSymbols, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lintConventionalCommit, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseCommitTrailers, parseConnectionString, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testGitignorePatterns, testPattern, testRegex, validateAria, validateEditorConfig, validateEnvKey, validateFenceLanguageTags, validatePackageExports, validateTsconfig };
|