@no-k/hermes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +88 -0
  3. package/bin/hermes.mjs +159 -0
  4. package/catalog.json +1084 -0
  5. package/lib/catalog.mjs +51 -0
  6. package/package.json +28 -0
  7. package/templates/algorithm/geometry/ccw/ccw.ts +25 -0
  8. package/templates/algorithm/geometry/ccw/index.ts +1 -0
  9. package/templates/algorithm/geometry/convex-hull/convex-hull.ts +43 -0
  10. package/templates/algorithm/geometry/convex-hull/index.ts +1 -0
  11. package/templates/algorithm/geometry/polygon-area/index.ts +1 -0
  12. package/templates/algorithm/geometry/polygon-area/polygon-area.ts +13 -0
  13. package/templates/algorithm/graph/bellman-ford/bellman-ford.ts +46 -0
  14. package/templates/algorithm/graph/bellman-ford/index.ts +1 -0
  15. package/templates/algorithm/graph/bfs/bfs.ts +21 -0
  16. package/templates/algorithm/graph/bfs/index.ts +1 -0
  17. package/templates/algorithm/graph/dfs/dfs.ts +22 -0
  18. package/templates/algorithm/graph/dfs/index.ts +1 -0
  19. package/templates/algorithm/graph/dijkstra/dijkstra.ts +37 -0
  20. package/templates/algorithm/graph/dijkstra/index.ts +1 -0
  21. package/templates/algorithm/graph/floyd-warshall/floyd-warshall.ts +17 -0
  22. package/templates/algorithm/graph/floyd-warshall/index.ts +1 -0
  23. package/templates/algorithm/graph/kruskal/index.ts +1 -0
  24. package/templates/algorithm/graph/kruskal/kruskal.ts +29 -0
  25. package/templates/algorithm/graph/prim/index.ts +1 -0
  26. package/templates/algorithm/graph/prim/prim.ts +44 -0
  27. package/templates/algorithm/graph/topology-sort/index.ts +1 -0
  28. package/templates/algorithm/graph/topology-sort/topology-sort.ts +31 -0
  29. package/templates/algorithm/search/binary-search/binary-search.ts +74 -0
  30. package/templates/algorithm/search/binary-search/index.ts +1 -0
  31. package/templates/algorithm/string/kmp/index.ts +1 -0
  32. package/templates/algorithm/string/kmp/kmp.ts +46 -0
  33. package/templates/algorithm/string/z-algorithm/index.ts +1 -0
  34. package/templates/algorithm/string/z-algorithm/z-algorithm.ts +41 -0
  35. package/templates/algorithm/tree/avl-tree/avl-tree.ts +197 -0
  36. package/templates/algorithm/tree/avl-tree/index.ts +1 -0
  37. package/templates/algorithm/tree/binary-search-tree/binary-search-tree.ts +144 -0
  38. package/templates/algorithm/tree/binary-search-tree/index.ts +1 -0
  39. package/templates/algorithm/tree/lca/index.ts +1 -0
  40. package/templates/algorithm/tree/lca/lca.ts +119 -0
  41. package/templates/array/chunk/chunk.ts +13 -0
  42. package/templates/array/chunk/index.ts +1 -0
  43. package/templates/array/compact/compact.ts +8 -0
  44. package/templates/array/compact/index.ts +1 -0
  45. package/templates/array/count-by/count-by.ts +12 -0
  46. package/templates/array/count-by/index.ts +1 -0
  47. package/templates/array/difference/difference.ts +6 -0
  48. package/templates/array/difference/index.ts +1 -0
  49. package/templates/array/drop/drop.ts +7 -0
  50. package/templates/array/drop/index.ts +1 -0
  51. package/templates/array/group-by/group-by.ts +18 -0
  52. package/templates/array/group-by/index.ts +1 -0
  53. package/templates/array/intersection/index.ts +1 -0
  54. package/templates/array/intersection/intersection.ts +15 -0
  55. package/templates/array/key-by/index.ts +1 -0
  56. package/templates/array/key-by/key-by.ts +11 -0
  57. package/templates/array/max-by/index.ts +1 -0
  58. package/templates/array/max-by/max-by.ts +20 -0
  59. package/templates/array/min-by/index.ts +1 -0
  60. package/templates/array/min-by/min-by.ts +20 -0
  61. package/templates/array/partition/index.ts +1 -0
  62. package/templates/array/partition/partition.ts +16 -0
  63. package/templates/array/range/index.ts +1 -0
  64. package/templates/array/range/range.ts +22 -0
  65. package/templates/array/sample/index.ts +1 -0
  66. package/templates/array/sample/sample.ts +10 -0
  67. package/templates/array/shuffle/index.ts +1 -0
  68. package/templates/array/shuffle/shuffle.ts +15 -0
  69. package/templates/array/sort-by/index.ts +1 -0
  70. package/templates/array/sort-by/sort-by.ts +32 -0
  71. package/templates/array/sum-by/index.ts +1 -0
  72. package/templates/array/sum-by/sum-by.ts +9 -0
  73. package/templates/array/take/index.ts +1 -0
  74. package/templates/array/take/take.ts +7 -0
  75. package/templates/array/union/index.ts +1 -0
  76. package/templates/array/union/union.ts +5 -0
  77. package/templates/array/unique/index.ts +1 -0
  78. package/templates/array/unique/unique.ts +5 -0
  79. package/templates/array/unique-by/index.ts +1 -0
  80. package/templates/array/unique-by/unique-by.ts +19 -0
  81. package/templates/array/windowed/index.ts +1 -0
  82. package/templates/array/windowed/windowed.ts +15 -0
  83. package/templates/array/zip/index.ts +1 -0
  84. package/templates/array/zip/zip.ts +11 -0
  85. package/templates/boolean/parse-boolean/index.ts +1 -0
  86. package/templates/boolean/parse-boolean/parse-boolean.ts +17 -0
  87. package/templates/boolean/toggle/index.ts +1 -0
  88. package/templates/boolean/toggle/toggle.ts +2 -0
  89. package/templates/boolean/xor/index.ts +1 -0
  90. package/templates/boolean/xor/xor.ts +2 -0
  91. package/templates/data-structure/deque/deque.ts +79 -0
  92. package/templates/data-structure/deque/index.ts +1 -0
  93. package/templates/data-structure/fenwick-tree/fenwick-tree.ts +76 -0
  94. package/templates/data-structure/fenwick-tree/index.ts +1 -0
  95. package/templates/data-structure/heap/heap.ts +88 -0
  96. package/templates/data-structure/heap/index.ts +3 -0
  97. package/templates/data-structure/heap/max-heap.ts +7 -0
  98. package/templates/data-structure/heap/min-heap.ts +7 -0
  99. package/templates/data-structure/priority-queue/index.ts +1 -0
  100. package/templates/data-structure/priority-queue/priority-queue.ts +44 -0
  101. package/templates/data-structure/queue/index.ts +1 -0
  102. package/templates/data-structure/queue/queue.ts +66 -0
  103. package/templates/data-structure/segment-tree/index.ts +1 -0
  104. package/templates/data-structure/segment-tree/segment-tree.ts +79 -0
  105. package/templates/data-structure/trie/index.ts +1 -0
  106. package/templates/data-structure/trie/trie.ts +104 -0
  107. package/templates/data-structure/union-find/index.ts +1 -0
  108. package/templates/data-structure/union-find/union-find.ts +79 -0
  109. package/templates/dom/attribute/attribute.ts +24 -0
  110. package/templates/dom/attribute/index.ts +1 -0
  111. package/templates/dom/class-name/class-name.ts +48 -0
  112. package/templates/dom/class-name/index.ts +1 -0
  113. package/templates/dom/is-element/index.ts +1 -0
  114. package/templates/dom/is-element/is-element.ts +20 -0
  115. package/templates/dom/query/index.ts +1 -0
  116. package/templates/dom/query/query.ts +7 -0
  117. package/templates/http/content-type/content-type.ts +130 -0
  118. package/templates/http/content-type/index.ts +1 -0
  119. package/templates/http/header/header.ts +56 -0
  120. package/templates/http/header/index.ts +1 -0
  121. package/templates/http/method/index.ts +1 -0
  122. package/templates/http/method/method.ts +25 -0
  123. package/templates/http/status/index.ts +1 -0
  124. package/templates/http/status/status.ts +191 -0
  125. package/templates/number/clamp/clamp.ts +11 -0
  126. package/templates/number/clamp/index.ts +1 -0
  127. package/templates/number/factorial/factorial.ts +15 -0
  128. package/templates/number/factorial/index.ts +1 -0
  129. package/templates/number/format-thousands/format-thousands.ts +24 -0
  130. package/templates/number/format-thousands/index.ts +1 -0
  131. package/templates/number/gcd/gcd.ts +13 -0
  132. package/templates/number/gcd/index.ts +1 -0
  133. package/templates/number/in-range/in-range.ts +3 -0
  134. package/templates/number/in-range/index.ts +1 -0
  135. package/templates/number/is-even/index.ts +1 -0
  136. package/templates/number/is-even/is-even.ts +5 -0
  137. package/templates/number/is-odd/index.ts +1 -0
  138. package/templates/number/is-odd/is-odd.ts +7 -0
  139. package/templates/number/lcm/index.ts +1 -0
  140. package/templates/number/lcm/lcm.ts +12 -0
  141. package/templates/number/lerp/index.ts +1 -0
  142. package/templates/number/lerp/lerp.ts +3 -0
  143. package/templates/number/percentage/index.ts +1 -0
  144. package/templates/number/percentage/percentage.ts +7 -0
  145. package/templates/number/random/index.ts +1 -0
  146. package/templates/number/random/random.ts +9 -0
  147. package/templates/number/random-int/index.ts +1 -0
  148. package/templates/number/random-int/random-int.ts +9 -0
  149. package/templates/number/round/index.ts +1 -0
  150. package/templates/number/round/round.ts +22 -0
  151. package/templates/number/safe-parse-number/index.ts +1 -0
  152. package/templates/number/safe-parse-number/safe-parse-number.ts +29 -0
  153. package/templates/number/to-ordinal/index.ts +1 -0
  154. package/templates/number/to-ordinal/to-ordinal.ts +28 -0
  155. package/templates/object/deep-clone/deep-clone.ts +47 -0
  156. package/templates/object/deep-clone/index.ts +1 -0
  157. package/templates/object/deep-equal/deep-equal.ts +66 -0
  158. package/templates/object/deep-equal/index.ts +1 -0
  159. package/templates/object/deep-merge/deep-merge.ts +49 -0
  160. package/templates/object/deep-merge/index.ts +1 -0
  161. package/templates/object/defaults/defaults.ts +14 -0
  162. package/templates/object/defaults/index.ts +1 -0
  163. package/templates/object/filter-object/filter-object.ts +11 -0
  164. package/templates/object/filter-object/index.ts +1 -0
  165. package/templates/object/get/get.ts +75 -0
  166. package/templates/object/get/index.ts +1 -0
  167. package/templates/object/has/has.ts +60 -0
  168. package/templates/object/has/index.ts +1 -0
  169. package/templates/object/invert/index.ts +1 -0
  170. package/templates/object/invert/invert.ts +13 -0
  171. package/templates/object/map-keys/index.ts +1 -0
  172. package/templates/object/map-keys/map-keys.ts +16 -0
  173. package/templates/object/map-values/index.ts +1 -0
  174. package/templates/object/map-values/map-values.ts +14 -0
  175. package/templates/object/omit/index.ts +1 -0
  176. package/templates/object/omit/omit.ts +15 -0
  177. package/templates/object/omit-by/index.ts +1 -0
  178. package/templates/object/omit-by/omit-by.ts +19 -0
  179. package/templates/object/pick/index.ts +1 -0
  180. package/templates/object/pick/pick.ts +15 -0
  181. package/templates/object/pick-by/index.ts +1 -0
  182. package/templates/object/pick-by/pick-by.ts +19 -0
  183. package/templates/object/set/index.ts +1 -0
  184. package/templates/object/set/set.ts +118 -0
  185. package/templates/string/capitalize/capitalize.ts +4 -0
  186. package/templates/string/capitalize/index.ts +1 -0
  187. package/templates/string/change-case/change-case.ts +98 -0
  188. package/templates/string/change-case/index.ts +1 -0
  189. package/templates/string/char/char.ts +14 -0
  190. package/templates/string/char/index.ts +1 -0
  191. package/templates/string/count-occurrences/count-occurrences.ts +20 -0
  192. package/templates/string/count-occurrences/index.ts +1 -0
  193. package/templates/string/escape-html/escape-html.ts +16 -0
  194. package/templates/string/escape-html/index.ts +1 -0
  195. package/templates/string/get-decorated-string/get-decorated-string.ts +7 -0
  196. package/templates/string/get-decorated-string/index.ts +1 -0
  197. package/templates/string/is-blank/index.ts +1 -0
  198. package/templates/string/is-blank/is-blank.ts +6 -0
  199. package/templates/string/mask/index.ts +1 -0
  200. package/templates/string/mask/mask.ts +30 -0
  201. package/templates/string/pad/index.ts +1 -0
  202. package/templates/string/pad/pad.ts +17 -0
  203. package/templates/string/random-string/index.ts +1 -0
  204. package/templates/string/random-string/random-string.ts +20 -0
  205. package/templates/string/reverse/index.ts +1 -0
  206. package/templates/string/reverse/reverse.ts +6 -0
  207. package/templates/string/slugify/index.ts +1 -0
  208. package/templates/string/slugify/slugify.ts +11 -0
  209. package/templates/string/strip-tags/index.ts +1 -0
  210. package/templates/string/strip-tags/strip-tags.ts +8 -0
  211. package/templates/string/template/index.ts +1 -0
  212. package/templates/string/template/template.ts +14 -0
  213. package/templates/string/truncate/index.ts +1 -0
  214. package/templates/string/truncate/truncate.ts +17 -0
  215. package/templates/string/truncate-middle/index.ts +1 -0
  216. package/templates/string/truncate-middle/truncate-middle.ts +25 -0
  217. package/templates/string/uuid/index.ts +1 -0
  218. package/templates/string/uuid/uuid.ts +9 -0
  219. package/templates/tailwindcss/class-variant/class-variant.ts +35 -0
  220. package/templates/tailwindcss/class-variant/index.ts +1 -0
  221. package/templates/tailwindcss/cn/cn.ts +29 -0
  222. package/templates/tailwindcss/cn/index.ts +1 -0
  223. package/templates/tailwindcss/create-tailwind-css/create-tailwind-css.ts +16 -0
  224. package/templates/tailwindcss/create-tailwind-css/index.ts +1 -0
  225. package/templates/tailwindcss/tw-merge-config/index.ts +1 -0
  226. package/templates/tailwindcss/tw-merge-config/tw-merge-config.ts +14 -0
  227. package/templates/type/get-type/get-type.ts +27 -0
  228. package/templates/type/get-type/index.ts +1 -0
  229. package/templates/type/is-type-of/index.ts +1 -0
  230. package/templates/type/is-type-of/is-type-of.ts +26 -0
  231. package/templates/util/mutex/index.ts +1 -0
  232. package/templates/util/mutex/mutex.ts +109 -0
  233. package/templates/util/url-parser/index.ts +1 -0
  234. package/templates/util/url-parser/url-parser.ts +44 -0
@@ -0,0 +1,51 @@
1
+ const itemNamePattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2
+
3
+ export function isSourcePath(value) {
4
+ return (
5
+ typeof value === "string" &&
6
+ value.endsWith(".ts") &&
7
+ !value.includes("\\") &&
8
+ !value.includes("\0") &&
9
+ !value.includes(":") &&
10
+ value.split("/").every((part) => part && part !== "." && part !== "..") &&
11
+ !/\.(test|spec|stories|config|d)\.ts$/.test(value)
12
+ );
13
+ }
14
+
15
+ export function validateCatalog(catalog) {
16
+ if (
17
+ catalog?.schemaVersion !== 1 ||
18
+ typeof catalog.version !== "string" ||
19
+ !Array.isArray(catalog.items) ||
20
+ catalog.items.length === 0
21
+ ) {
22
+ throw new Error("Invalid Hermes catalog.");
23
+ }
24
+ const names = new Set();
25
+ for (const item of catalog.items) {
26
+ if (
27
+ !item ||
28
+ typeof item.name !== "string" ||
29
+ !itemNamePattern.test(item.name) ||
30
+ names.has(item.name) ||
31
+ typeof item.description !== "string" ||
32
+ !Array.isArray(item.files) ||
33
+ item.files.length === 0 ||
34
+ !item.files.every(isSourcePath) ||
35
+ new Set(item.files).size !== item.files.length ||
36
+ (item.runtime !== undefined && !["node", "dom"].includes(item.runtime))
37
+ ) {
38
+ throw new Error("Invalid or duplicate Hermes item: " + item?.name);
39
+ }
40
+ for (const values of [item.dependencies, item.devDependencies ?? []]) {
41
+ if (
42
+ !Array.isArray(values) ||
43
+ !values.every((value) => typeof value === "string" && /^[^\s]+@[^\s]+$/.test(value))
44
+ ) {
45
+ throw new Error("Invalid dependencies for " + item.name);
46
+ }
47
+ }
48
+ names.add(item.name);
49
+ }
50
+ return catalog;
51
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@no-k/hermes",
3
+ "version": "0.1.0",
4
+ "description": "Add individual TypeScript utilities to your project with the Hermes CLI.",
5
+ "license": "ISC",
6
+ "files": ["bin", "lib", "templates", "catalog.json", "README.md", "LICENSE"],
7
+ "keywords": ["cli", "typescript", "utilities"],
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/no-k/hermes.git",
11
+ "directory": "packages/cli"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org/",
16
+ "provenance": false
17
+ },
18
+ "scripts": {
19
+ "prepack": "pnpm --workspace-root run build:cli"
20
+ },
21
+ "type": "module",
22
+ "bin": {
23
+ "hermes": "./bin/hermes.mjs"
24
+ },
25
+ "engines": {
26
+ "node": ">=22"
27
+ }
28
+ }
@@ -0,0 +1,25 @@
1
+ export type Point = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+
6
+ export const ccw = (a: Point, b: Point, c: Point) => {
7
+ const cross = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
8
+
9
+ if (cross > 0) {
10
+ return 1;
11
+ }
12
+
13
+ if (cross < 0) {
14
+ return -1;
15
+ }
16
+
17
+ return 0;
18
+ };
19
+
20
+ export const distanceSquare = (a: Point, b: Point) => {
21
+ const dx = a.x - b.x;
22
+ const dy = a.y - b.y;
23
+
24
+ return dx * dx + dy * dy;
25
+ };
@@ -0,0 +1 @@
1
+ export * from "./ccw";
@@ -0,0 +1,43 @@
1
+ import { type Point, ccw } from "../ccw/index";
2
+
3
+ const comparePoint = (a: Point, b: Point) => {
4
+ if (a.x !== b.x) {
5
+ return a.x - b.x;
6
+ }
7
+
8
+ return a.y - b.y;
9
+ };
10
+
11
+ const samePoint = (a: Point, b: Point) => a.x === b.x && a.y === b.y;
12
+
13
+ export const convexHull = (points: Point[]) => {
14
+ const sorted = [...points].sort(comparePoint).filter((point, index, values) => {
15
+ return index === 0 || !samePoint(point, values[index - 1]);
16
+ });
17
+
18
+ if (sorted.length <= 1) {
19
+ return sorted;
20
+ }
21
+
22
+ const lower: Point[] = [];
23
+ for (const point of sorted) {
24
+ while (lower.length >= 2 && ccw(lower[lower.length - 2], lower[lower.length - 1], point) <= 0) {
25
+ lower.pop();
26
+ }
27
+ lower.push(point);
28
+ }
29
+
30
+ const upper: Point[] = [];
31
+ for (let index = sorted.length - 1; index >= 0; index -= 1) {
32
+ const point = sorted[index];
33
+ while (upper.length >= 2 && ccw(upper[upper.length - 2], upper[upper.length - 1], point) <= 0) {
34
+ upper.pop();
35
+ }
36
+ upper.push(point);
37
+ }
38
+
39
+ lower.pop();
40
+ upper.pop();
41
+
42
+ return [...lower, ...upper];
43
+ };
@@ -0,0 +1 @@
1
+ export * from "./convex-hull";
@@ -0,0 +1 @@
1
+ export * from "./polygon-area";
@@ -0,0 +1,13 @@
1
+ import type { Point } from "../ccw/index";
2
+
3
+ export const polygonArea = (points: Point[]) => {
4
+ let doubledArea = 0;
5
+
6
+ for (let index = 0; index < points.length; index += 1) {
7
+ const current = points[index];
8
+ const next = points[(index + 1) % points.length];
9
+ doubledArea += current.x * next.y - current.y * next.x;
10
+ }
11
+
12
+ return Math.abs(doubledArea) / 2;
13
+ };
@@ -0,0 +1,46 @@
1
+ export type DirectedWeightedEdge<T> = {
2
+ from: T;
3
+ to: T;
4
+ weight: number;
5
+ };
6
+
7
+ export const bellmanFord = <T>(nodes: Iterable<T>, edges: DirectedWeightedEdge<T>[], start: T) => {
8
+ const distances = new Map<T, number>();
9
+
10
+ for (const node of nodes) {
11
+ distances.set(node, Number.POSITIVE_INFINITY);
12
+ }
13
+ distances.set(start, 0);
14
+
15
+ const nodeList = [...distances.keys()];
16
+
17
+ for (let count = 0; count < nodeList.length - 1; count += 1) {
18
+ let updated = false;
19
+
20
+ for (const edge of edges) {
21
+ const fromDistance = distances.get(edge.from) ?? Number.POSITIVE_INFINITY;
22
+ const toDistance = distances.get(edge.to) ?? Number.POSITIVE_INFINITY;
23
+
24
+ if (fromDistance !== Number.POSITIVE_INFINITY && fromDistance + edge.weight < toDistance) {
25
+ distances.set(edge.to, fromDistance + edge.weight);
26
+ updated = true;
27
+ }
28
+ }
29
+
30
+ if (!updated) {
31
+ break;
32
+ }
33
+ }
34
+
35
+ const hasNegativeCycle = edges.some((edge) => {
36
+ const fromDistance = distances.get(edge.from) ?? Number.POSITIVE_INFINITY;
37
+ const toDistance = distances.get(edge.to) ?? Number.POSITIVE_INFINITY;
38
+
39
+ return fromDistance !== Number.POSITIVE_INFINITY && fromDistance + edge.weight < toDistance;
40
+ });
41
+
42
+ return {
43
+ distances,
44
+ hasNegativeCycle,
45
+ };
46
+ };
@@ -0,0 +1 @@
1
+ export * from "./bellman-ford";
@@ -0,0 +1,21 @@
1
+ export const bfs = <T>(start: T, getNeighbors: (node: T) => Iterable<T>) => {
2
+ const visited = new Set<T>([start]);
3
+ const queue: T[] = [start];
4
+ const order: T[] = [];
5
+
6
+ for (let index = 0; index < queue.length; index += 1) {
7
+ const node = queue[index];
8
+ order.push(node);
9
+
10
+ for (const next of getNeighbors(node)) {
11
+ if (visited.has(next)) {
12
+ continue;
13
+ }
14
+
15
+ visited.add(next);
16
+ queue.push(next);
17
+ }
18
+ }
19
+
20
+ return order;
21
+ };
@@ -0,0 +1 @@
1
+ export * from "./bfs";
@@ -0,0 +1,22 @@
1
+ export const dfs = <T>(start: T, getNeighbors: (node: T) => Iterable<T>) => {
2
+ const visited = new Set<T>();
3
+ const stack: T[] = [start];
4
+ const order: T[] = [];
5
+
6
+ while (stack.length) {
7
+ const node = stack.pop() as T;
8
+ if (visited.has(node)) {
9
+ continue;
10
+ }
11
+
12
+ visited.add(node);
13
+ order.push(node);
14
+
15
+ const neighbors = [...getNeighbors(node)];
16
+ for (let index = neighbors.length - 1; index >= 0; index -= 1) {
17
+ stack.push(neighbors[index]);
18
+ }
19
+ }
20
+
21
+ return order;
22
+ };
@@ -0,0 +1 @@
1
+ export * from "./dfs";
@@ -0,0 +1,37 @@
1
+ import { PriorityQueue } from "../../../data-structure/priority-queue/index";
2
+
3
+ export type WeightedEdge<T> = {
4
+ to: T;
5
+ weight: number;
6
+ };
7
+
8
+ export const dijkstra = <T>(start: T, getEdges: (node: T) => Iterable<WeightedEdge<T>>) => {
9
+ const distances = new Map<T, number>([[start, 0]]);
10
+ const queue = new PriorityQueue<{ node: T; distance: number }>({
11
+ compare: (a, b) => a.distance - b.distance,
12
+ });
13
+
14
+ queue.enqueue({ node: start, distance: 0 });
15
+
16
+ while (!queue.isEmpty()) {
17
+ const current = queue.dequeue() as { node: T; distance: number };
18
+
19
+ if (current.distance > (distances.get(current.node) as number)) {
20
+ continue;
21
+ }
22
+
23
+ for (const edge of getEdges(current.node)) {
24
+ const nextDistance = current.distance + edge.weight;
25
+ const previousDistance = distances.get(edge.to);
26
+
27
+ if (previousDistance !== undefined && previousDistance <= nextDistance) {
28
+ continue;
29
+ }
30
+
31
+ distances.set(edge.to, nextDistance);
32
+ queue.enqueue({ node: edge.to, distance: nextDistance });
33
+ }
34
+ }
35
+
36
+ return distances;
37
+ };
@@ -0,0 +1 @@
1
+ export * from "./dijkstra";
@@ -0,0 +1,17 @@
1
+ export const floydWarshall = (matrix: number[][]) => {
2
+ const distance = matrix.map((row) => [...row]);
3
+ const size = distance.length;
4
+
5
+ for (let mid = 0; mid < size; mid += 1) {
6
+ for (let from = 0; from < size; from += 1) {
7
+ for (let to = 0; to < size; to += 1) {
8
+ const next = distance[from][mid] + distance[mid][to];
9
+ if (next < distance[from][to]) {
10
+ distance[from][to] = next;
11
+ }
12
+ }
13
+ }
14
+ }
15
+
16
+ return distance;
17
+ };
@@ -0,0 +1 @@
1
+ export * from "./floyd-warshall";
@@ -0,0 +1 @@
1
+ export * from "./kruskal";
@@ -0,0 +1,29 @@
1
+ import { UnionFind } from "../../../data-structure/union-find/index";
2
+
3
+ export type WeightedUndirectedEdge<T> = {
4
+ from: T;
5
+ to: T;
6
+ weight: number;
7
+ };
8
+
9
+ export const kruskal = <T>(nodes: Iterable<T>, edges: WeightedUndirectedEdge<T>[]) => {
10
+ const unionFind = new UnionFind(nodes);
11
+ const selected: WeightedUndirectedEdge<T>[] = [];
12
+ let totalWeight = 0;
13
+
14
+ const sortedEdges = [...edges].sort((a, b) => a.weight - b.weight);
15
+
16
+ for (const edge of sortedEdges) {
17
+ if (!unionFind.union(edge.from, edge.to)) {
18
+ continue;
19
+ }
20
+
21
+ selected.push(edge);
22
+ totalWeight += edge.weight;
23
+ }
24
+
25
+ return {
26
+ edges: selected,
27
+ totalWeight,
28
+ };
29
+ };
@@ -0,0 +1 @@
1
+ export * from "./prim";
@@ -0,0 +1,44 @@
1
+ import { PriorityQueue } from "../../../data-structure/priority-queue/index";
2
+ import type { WeightedEdge } from "../dijkstra/index";
3
+
4
+ type QueueItem<T> = {
5
+ from: T | null;
6
+ to: T;
7
+ weight: number;
8
+ };
9
+
10
+ export const prim = <T>(start: T, getEdges: (node: T) => Iterable<WeightedEdge<T>>) => {
11
+ const visited = new Set<T>();
12
+ const selected: Array<{ from: T; to: T; weight: number }> = [];
13
+ const queue = new PriorityQueue<QueueItem<T>>({
14
+ compare: (a, b) => a.weight - b.weight,
15
+ });
16
+ let totalWeight = 0;
17
+
18
+ queue.enqueue({ from: null, to: start, weight: 0 });
19
+
20
+ while (!queue.isEmpty()) {
21
+ const current = queue.dequeue() as QueueItem<T>;
22
+ if (visited.has(current.to)) {
23
+ continue;
24
+ }
25
+
26
+ visited.add(current.to);
27
+
28
+ if (current.from !== null) {
29
+ selected.push({ from: current.from, to: current.to, weight: current.weight });
30
+ totalWeight += current.weight;
31
+ }
32
+
33
+ for (const edge of getEdges(current.to)) {
34
+ if (!visited.has(edge.to)) {
35
+ queue.enqueue({ from: current.to, to: edge.to, weight: edge.weight });
36
+ }
37
+ }
38
+ }
39
+
40
+ return {
41
+ edges: selected,
42
+ totalWeight,
43
+ };
44
+ };
@@ -0,0 +1 @@
1
+ export * from "./topology-sort";
@@ -0,0 +1,31 @@
1
+ export const topologicalSort = <T>(nodes: Iterable<T>, getNeighbors: (node: T) => Iterable<T>) => {
2
+ const visited = new Set<T>();
3
+ const visiting = new Set<T>();
4
+ const result: T[] = [];
5
+
6
+ const visit = (node: T) => {
7
+ if (visited.has(node)) {
8
+ return;
9
+ }
10
+
11
+ if (visiting.has(node)) {
12
+ throw new Error("cycle detected");
13
+ }
14
+
15
+ visiting.add(node);
16
+
17
+ for (const next of getNeighbors(node)) {
18
+ visit(next);
19
+ }
20
+
21
+ visiting.delete(node);
22
+ visited.add(node);
23
+ result.push(node);
24
+ };
25
+
26
+ for (const node of nodes) {
27
+ visit(node);
28
+ }
29
+
30
+ return result.reverse();
31
+ };
@@ -0,0 +1,74 @@
1
+ const defaultCompare = <T>(value: T, target: T) => {
2
+ if (value < target) {
3
+ return -1;
4
+ }
5
+
6
+ if (value > target) {
7
+ return 1;
8
+ }
9
+
10
+ return 0;
11
+ };
12
+
13
+ export const lowerBound = <T>(values: T[], target: T, compare = defaultCompare<T>) => {
14
+ let left = 0;
15
+ let right = values.length;
16
+
17
+ while (left < right) {
18
+ const mid = Math.floor((left + right) / 2);
19
+
20
+ if (compare(values[mid], target) < 0) {
21
+ left = mid + 1;
22
+ } else {
23
+ right = mid;
24
+ }
25
+ }
26
+
27
+ return left;
28
+ };
29
+
30
+ export const upperBound = <T>(values: T[], target: T, compare = defaultCompare<T>) => {
31
+ let left = 0;
32
+ let right = values.length;
33
+
34
+ while (left < right) {
35
+ const mid = Math.floor((left + right) / 2);
36
+
37
+ if (compare(values[mid], target) <= 0) {
38
+ left = mid + 1;
39
+ } else {
40
+ right = mid;
41
+ }
42
+ }
43
+
44
+ return left;
45
+ };
46
+
47
+ export const binarySearch = <T>(values: T[], target: T, compare = defaultCompare<T>) => {
48
+ const index = lowerBound(values, target, compare);
49
+
50
+ if (index >= values.length || compare(values[index], target) !== 0) {
51
+ return -1;
52
+ }
53
+
54
+ return index;
55
+ };
56
+
57
+ export const binarySearchAnswer = (left: number, right: number, canUse: (value: number) => boolean) => {
58
+ let low = left;
59
+ let high = right;
60
+ let answer = right + 1;
61
+
62
+ while (low <= high) {
63
+ const mid = Math.floor((low + high) / 2);
64
+
65
+ if (canUse(mid)) {
66
+ answer = mid;
67
+ high = mid - 1;
68
+ } else {
69
+ low = mid + 1;
70
+ }
71
+ }
72
+
73
+ return answer;
74
+ };
@@ -0,0 +1 @@
1
+ export * from "./binary-search";
@@ -0,0 +1 @@
1
+ export * from "./kmp";
@@ -0,0 +1,46 @@
1
+ export const buildPrefixTable = (pattern: string) => {
2
+ const table = Array(pattern.length).fill(0);
3
+ let matched = 0;
4
+
5
+ for (let index = 1; index < pattern.length; index += 1) {
6
+ while (matched > 0 && pattern[index] !== pattern[matched]) {
7
+ matched = table[matched - 1];
8
+ }
9
+
10
+ if (pattern[index] === pattern[matched]) {
11
+ matched += 1;
12
+ table[index] = matched;
13
+ }
14
+ }
15
+
16
+ return table;
17
+ };
18
+
19
+ export const kmpSearch = (text: string, pattern: string) => {
20
+ if (!pattern.length) {
21
+ return Array.from({ length: text.length + 1 }, (_, index) => index);
22
+ }
23
+
24
+ const table = buildPrefixTable(pattern);
25
+ const result: number[] = [];
26
+ let matched = 0;
27
+
28
+ for (let index = 0; index < text.length; index += 1) {
29
+ while (matched > 0 && text[index] !== pattern[matched]) {
30
+ matched = table[matched - 1];
31
+ }
32
+
33
+ if (text[index] !== pattern[matched]) {
34
+ continue;
35
+ }
36
+
37
+ matched += 1;
38
+
39
+ if (matched === pattern.length) {
40
+ result.push(index - pattern.length + 1);
41
+ matched = table[matched - 1];
42
+ }
43
+ }
44
+
45
+ return result;
46
+ };
@@ -0,0 +1 @@
1
+ export * from "./z-algorithm";
@@ -0,0 +1,41 @@
1
+ export const buildZArray = (value: string) => {
2
+ const z = Array(value.length).fill(0);
3
+ let left = 0;
4
+ let right = 0;
5
+
6
+ for (let index = 1; index < value.length; index += 1) {
7
+ if (index <= right) {
8
+ z[index] = Math.min(right - index + 1, z[index - left]);
9
+ }
10
+
11
+ while (index + z[index] < value.length && value[z[index]] === value[index + z[index]]) {
12
+ z[index] += 1;
13
+ }
14
+
15
+ if (index + z[index] - 1 > right) {
16
+ left = index;
17
+ right = index + z[index] - 1;
18
+ }
19
+ }
20
+
21
+ return z;
22
+ };
23
+
24
+ export const zSearch = (text: string, pattern: string) => {
25
+ if (!pattern.length) {
26
+ return Array.from({ length: text.length + 1 }, (_, index) => index);
27
+ }
28
+
29
+ const separator = "\0";
30
+ const z = buildZArray(`${pattern}${separator}${text}`);
31
+ const result: number[] = [];
32
+ const offset = pattern.length + 1;
33
+
34
+ for (let index = offset; index < z.length; index += 1) {
35
+ if (z[index] >= pattern.length) {
36
+ result.push(index - offset);
37
+ }
38
+ }
39
+
40
+ return result;
41
+ };