stack-dev 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 (204) hide show
  1. package/.idea/modules.xml +8 -0
  2. package/.idea/prettier.xml +7 -0
  3. package/.idea/stack-dev.iml +12 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/apps/cli/eslint.config.mjs +3 -0
  6. package/apps/cli/node_modules/.bin/acorn +21 -0
  7. package/apps/cli/node_modules/.bin/esbuild +21 -0
  8. package/apps/cli/node_modules/.bin/eslint +21 -0
  9. package/apps/cli/node_modules/.bin/glob +21 -0
  10. package/apps/cli/node_modules/.bin/json5 +21 -0
  11. package/apps/cli/node_modules/.bin/prettier +21 -0
  12. package/apps/cli/node_modules/.bin/stack-prettier +21 -0
  13. package/apps/cli/node_modules/.bin/tsc +21 -0
  14. package/apps/cli/node_modules/.bin/tsserver +21 -0
  15. package/apps/cli/node_modules/.bin/tsup +21 -0
  16. package/apps/cli/node_modules/.bin/tsup-node +21 -0
  17. package/apps/cli/node_modules/.bin/yaml +21 -0
  18. package/apps/cli/package.json +35 -0
  19. package/apps/cli/prettier.config.mjs +3 -0
  20. package/apps/cli/src/file-generator/file-generator-imp.ts +20 -0
  21. package/apps/cli/src/file-generator/file-generator.ts +5 -0
  22. package/apps/cli/src/file-generator/index.ts +3 -0
  23. package/apps/cli/src/file-generator/package-json-generator.ts +23 -0
  24. package/apps/cli/src/index.ts +185 -0
  25. package/apps/cli/src/link-packages.ts +65 -0
  26. package/apps/cli/src/package-json/dependency.ts +28 -0
  27. package/apps/cli/src/package-json/index.ts +3 -0
  28. package/apps/cli/src/package-json/package-json.ts +269 -0
  29. package/apps/cli/src/packages/create-config-package.ts +29 -0
  30. package/apps/cli/src/packages/index.ts +4 -0
  31. package/apps/cli/src/packages/library-package/create-library-package.ts +85 -0
  32. package/apps/cli/src/packages/library-package/files/add-file-generator.ts +8 -0
  33. package/apps/cli/src/packages/library-package/files/add-spec-file-generator.ts +17 -0
  34. package/apps/cli/src/packages/library-package/files/eslint-config-file-generator.ts +11 -0
  35. package/apps/cli/src/packages/library-package/files/index-file-generator.ts +9 -0
  36. package/apps/cli/src/packages/library-package/files/prettier-config-file-generator.ts +11 -0
  37. package/apps/cli/src/packages/library-package/files/tsconfig-file-generator.ts +15 -0
  38. package/apps/cli/src/packages/library-package/files/tsup-config-file-generator.ts +23 -0
  39. package/apps/cli/src/packages/library-package/files/vitest-config-file-generator.ts +19 -0
  40. package/apps/cli/src/packages/library-package/index.ts +1 -0
  41. package/apps/cli/src/packages/react-package/create-react-package.ts +25 -0
  42. package/apps/cli/src/packages/react-package/create-tailwind-react-package.ts +30 -0
  43. package/apps/cli/src/packages/react-package/create-unstyled-react-package.ts +3 -0
  44. package/apps/cli/src/packages/react-package/css-react-package/create-css-react-package.ts +103 -0
  45. package/apps/cli/src/packages/react-package/css-react-package/files/button-css-module-file-generator.ts +16 -0
  46. package/apps/cli/src/packages/react-package/css-react-package/files/button-file-generator.ts +14 -0
  47. package/apps/cli/src/packages/react-package/css-react-package/files/button-spec-file-generator.ts +33 -0
  48. package/apps/cli/src/packages/react-package/css-react-package/files/eslint-config-file-generator.ts +18 -0
  49. package/apps/cli/src/packages/react-package/css-react-package/files/index-file-generator.ts +9 -0
  50. package/apps/cli/src/packages/react-package/css-react-package/files/prettier-config-file-generator.ts +11 -0
  51. package/apps/cli/src/packages/react-package/css-react-package/files/tsconfig-file-generator.ts +15 -0
  52. package/apps/cli/src/packages/react-package/css-react-package/files/tsup-config-file-generator.ts +24 -0
  53. package/apps/cli/src/packages/react-package/css-react-package/files/vitest-config-file-generator.ts +23 -0
  54. package/apps/cli/src/packages/react-package/index.ts +1 -0
  55. package/apps/cli/src/packages/react-package/styled-components-react-package/create-styled-components-react-package.ts +112 -0
  56. package/apps/cli/src/packages/react-package/styled-components-react-package/files/button-file-generator.ts +30 -0
  57. package/apps/cli/src/packages/react-package/styled-components-react-package/files/button-spec-file-generator.ts +33 -0
  58. package/apps/cli/src/packages/react-package/styled-components-react-package/files/eslint-config-file-generator.ts +18 -0
  59. package/apps/cli/src/packages/react-package/styled-components-react-package/files/index-file-generator.ts +9 -0
  60. package/apps/cli/src/packages/react-package/styled-components-react-package/files/prettier-config-file-generator.ts +11 -0
  61. package/apps/cli/src/packages/react-package/styled-components-react-package/files/tsconfig-file-generator.ts +15 -0
  62. package/apps/cli/src/packages/react-package/styled-components-react-package/files/tsup-config-file-generator.ts +21 -0
  63. package/apps/cli/src/packages/react-package/styled-components-react-package/files/vitest-config-file-generator.ts +23 -0
  64. package/apps/cli/src/packages/vite-react-app/create-vite-react-app.ts +79 -0
  65. package/apps/cli/src/packages/vite-react-app/files/app-file-generator.ts +28 -0
  66. package/apps/cli/src/packages/vite-react-app/files/eslint-config-file-generator.ts +11 -0
  67. package/apps/cli/src/packages/vite-react-app/files/index-html-file-generator.ts +20 -0
  68. package/apps/cli/src/packages/vite-react-app/files/main-file-generator.ts +14 -0
  69. package/apps/cli/src/packages/vite-react-app/files/prettier-config-file-generator.ts +11 -0
  70. package/apps/cli/src/packages/vite-react-app/files/tsconfig-file-generator.ts +15 -0
  71. package/apps/cli/src/packages/vite-react-app/files/vite-config-file-generator.ts +17 -0
  72. package/apps/cli/src/packages/vite-react-app/files/vitest-config-file-generator.ts +19 -0
  73. package/apps/cli/src/tsconfig/compiler-options.ts +83 -0
  74. package/apps/cli/src/tsconfig/index.ts +4 -0
  75. package/apps/cli/src/tsconfig/reference.ts +21 -0
  76. package/apps/cli/src/tsconfig/tsconfig.ts +137 -0
  77. package/apps/cli/src/unlink-packages.ts +47 -0
  78. package/apps/cli/src/utils/package-generator.ts +41 -0
  79. package/apps/cli/src/utils/package-type.ts +44 -0
  80. package/apps/cli/src/utils/package.ts +126 -0
  81. package/apps/cli/src/utils/style-type.ts +41 -0
  82. package/apps/cli/src/utils/utils.ts +28 -0
  83. package/apps/cli/src/utils/workspace.ts +78 -0
  84. package/apps/cli/src/workspace/create-workspace.ts +39 -0
  85. package/apps/cli/src/workspace/index.ts +1 -0
  86. package/apps/cli/src/workspace/root-package.ts +195 -0
  87. package/apps/cli/src/workspace/typescript-config.ts +84 -0
  88. package/apps/cli/tsconfig.json +14 -0
  89. package/apps/cli/tsup.config.ts +16 -0
  90. package/apps/demo/eslint.config.mjs +3 -0
  91. package/apps/demo/index.html +12 -0
  92. package/apps/demo/node_modules/.bin/browserslist +21 -0
  93. package/apps/demo/node_modules/.bin/eslint +21 -0
  94. package/apps/demo/node_modules/.bin/prettier +21 -0
  95. package/apps/demo/node_modules/.bin/tsc +21 -0
  96. package/apps/demo/node_modules/.bin/tsserver +21 -0
  97. package/apps/demo/node_modules/.bin/vite +21 -0
  98. package/apps/demo/node_modules/.vite/deps/_metadata.json +52 -0
  99. package/apps/demo/node_modules/.vite/deps/chunk-IGB2AZES.js +1930 -0
  100. package/apps/demo/node_modules/.vite/deps/chunk-IGB2AZES.js.map +7 -0
  101. package/apps/demo/node_modules/.vite/deps/chunk-NEPDRNXC.js +21626 -0
  102. package/apps/demo/node_modules/.vite/deps/chunk-NEPDRNXC.js.map +7 -0
  103. package/apps/demo/node_modules/.vite/deps/package.json +3 -0
  104. package/apps/demo/node_modules/.vite/deps/react-dom.js +6 -0
  105. package/apps/demo/node_modules/.vite/deps/react-dom.js.map +7 -0
  106. package/apps/demo/node_modules/.vite/deps/react-dom_client.js +38 -0
  107. package/apps/demo/node_modules/.vite/deps/react-dom_client.js.map +7 -0
  108. package/apps/demo/node_modules/.vite/deps/react.js +5 -0
  109. package/apps/demo/node_modules/.vite/deps/react.js.map +7 -0
  110. package/apps/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +911 -0
  111. package/apps/demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  112. package/apps/demo/node_modules/.vite/deps/react_jsx-runtime.js +923 -0
  113. package/apps/demo/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
  114. package/apps/demo/node_modules/.vite/deps/styled-components.js +1366 -0
  115. package/apps/demo/node_modules/.vite/deps/styled-components.js.map +7 -0
  116. package/apps/demo/package.json +32 -0
  117. package/apps/demo/prettier.config.mjs +3 -0
  118. package/apps/demo/src/App.tsx +50 -0
  119. package/apps/demo/src/main.tsx +9 -0
  120. package/apps/demo/tsconfig.json +17 -0
  121. package/apps/demo/vite.config.ts +9 -0
  122. package/apps/demo/vitest.config.ts +11 -0
  123. package/configs/eslint-config/base.mjs +15 -0
  124. package/configs/eslint-config/node_modules/.bin/acorn +21 -0
  125. package/configs/eslint-config/node_modules/.bin/eslint +21 -0
  126. package/configs/eslint-config/node_modules/.bin/tsc +21 -0
  127. package/configs/eslint-config/node_modules/.bin/tsserver +21 -0
  128. package/configs/eslint-config/package.json +12 -0
  129. package/configs/eslint-config/react.mjs +17 -0
  130. package/configs/prettier-config/base.mjs +11 -0
  131. package/configs/prettier-config/node_modules/.bin/prettier +21 -0
  132. package/configs/prettier-config/node_modules/.bin/tsc +21 -0
  133. package/configs/prettier-config/node_modules/.bin/tsserver +21 -0
  134. package/configs/prettier-config/package.json +9 -0
  135. package/configs/typescript-config/global.d.ts +12 -0
  136. package/configs/typescript-config/node_modules/.bin/tsc +21 -0
  137. package/configs/typescript-config/node_modules/.bin/tsserver +21 -0
  138. package/configs/typescript-config/package.json +7 -0
  139. package/configs/typescript-config/tsconfig.base.json +19 -0
  140. package/configs/typescript-config/tsconfig.node.json +6 -0
  141. package/configs/typescript-config/tsconfig.react.json +8 -0
  142. package/package.json +16 -0
  143. package/packages/core/eslint.config.mjs +3 -0
  144. package/packages/core/node_modules/.bin/eslint +21 -0
  145. package/packages/core/node_modules/.bin/prettier +21 -0
  146. package/packages/core/node_modules/.bin/tsc +21 -0
  147. package/packages/core/node_modules/.bin/tsserver +21 -0
  148. package/packages/core/node_modules/.bin/tsup +21 -0
  149. package/packages/core/node_modules/.bin/tsup-node +21 -0
  150. package/packages/core/node_modules/.bin/vite +21 -0
  151. package/packages/core/node_modules/.bin/vitest +21 -0
  152. package/packages/core/node_modules/.bin/yaml +21 -0
  153. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  154. package/packages/core/package.json +35 -0
  155. package/packages/core/prettier.config.mjs +3 -0
  156. package/packages/core/src/are-objects-equal.ts +26 -0
  157. package/packages/core/src/have-same-items.ts +84 -0
  158. package/packages/core/src/index.ts +6 -0
  159. package/packages/core/src/snapshot.ts +11 -0
  160. package/packages/core/src/sort-keys.ts +7 -0
  161. package/packages/core/src/spec/are-objects-equal.spec.ts +30 -0
  162. package/packages/core/src/spec/have-same-items.spec.ts +29 -0
  163. package/packages/core/src/spec/sort-keys.spec.ts +57 -0
  164. package/packages/core/tsconfig.json +7 -0
  165. package/packages/core/tsup.config.ts +15 -0
  166. package/packages/core/vitest.config.mts +11 -0
  167. package/packages/react-css/eslint.config.mjs +10 -0
  168. package/packages/react-css/node_modules/.bin/esbuild +21 -0
  169. package/packages/react-css/node_modules/.bin/eslint +21 -0
  170. package/packages/react-css/node_modules/.bin/prettier +21 -0
  171. package/packages/react-css/node_modules/.bin/tsc +21 -0
  172. package/packages/react-css/node_modules/.bin/tsserver +21 -0
  173. package/packages/react-css/node_modules/.bin/tsup +21 -0
  174. package/packages/react-css/node_modules/.bin/tsup-node +21 -0
  175. package/packages/react-css/node_modules/.bin/vitest +21 -0
  176. package/packages/react-css/node_modules/.bin/yaml +21 -0
  177. package/packages/react-css/package.json +50 -0
  178. package/packages/react-css/prettier.config.mjs +3 -0
  179. package/packages/react-css/src/button.module.css +8 -0
  180. package/packages/react-css/src/button.spec.tsx +25 -0
  181. package/packages/react-css/src/button.tsx +11 -0
  182. package/packages/react-css/src/index.ts +1 -0
  183. package/packages/react-css/tsconfig.json +7 -0
  184. package/packages/react-css/tsup.config.ts +17 -0
  185. package/packages/react-css/vitest.config.ts +15 -0
  186. package/packages/react-styled-components/eslint.config.mjs +10 -0
  187. package/packages/react-styled-components/node_modules/.bin/eslint +21 -0
  188. package/packages/react-styled-components/node_modules/.bin/prettier +21 -0
  189. package/packages/react-styled-components/node_modules/.bin/tsc +21 -0
  190. package/packages/react-styled-components/node_modules/.bin/tsserver +21 -0
  191. package/packages/react-styled-components/node_modules/.bin/tsup +21 -0
  192. package/packages/react-styled-components/node_modules/.bin/tsup-node +21 -0
  193. package/packages/react-styled-components/node_modules/.bin/vitest +21 -0
  194. package/packages/react-styled-components/node_modules/.bin/yaml +21 -0
  195. package/packages/react-styled-components/package.json +51 -0
  196. package/packages/react-styled-components/prettier.config.mjs +3 -0
  197. package/packages/react-styled-components/src/button.spec.tsx +27 -0
  198. package/packages/react-styled-components/src/button.tsx +21 -0
  199. package/packages/react-styled-components/src/index.ts +1 -0
  200. package/packages/react-styled-components/tsconfig.json +7 -0
  201. package/packages/react-styled-components/tsup.config.ts +16 -0
  202. package/packages/react-styled-components/vitest.config.ts +15 -0
  203. package/pnpm-workspace.yaml +4 -0
  204. package/turbo.json +13 -0
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules/vitest/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules/vitest/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/bin.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/bin.mjs" "$@"
21
+ fi
@@ -0,0 +1 @@
1
+ {"version":"3.2.4","results":[[":src/spec/have-same-items.spec.ts",{"duration":4.46448300000003,"failed":false}],[":src/arrays/spec/have-same-items.spec.ts",{"duration":0,"failed":true}],[":src/array/spec/have-same-items.spec.ts",{"duration":4.16478300000017,"failed":false}],[":src/spec/are-objects-equal.spec.ts",{"duration":3.64540199999999,"failed":false}],[":src/spec/sort-keys.spec.ts",{"duration":18.987310000004072,"failed":false}]]}
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@stack-dev/core",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "devDependencies": {
6
+ "@stack-dev/eslint-config": "workspace:*",
7
+ "@stack-dev/prettier-config": "workspace:*",
8
+ "@stack-dev/typescript-config": "workspace:*",
9
+ "eslint": "^9.32.0",
10
+ "prettier": "^3.6.2",
11
+ "prettier-plugin-organize-imports": "^4.2.0",
12
+ "tsup": "^7.3.0",
13
+ "vitest": "^3.2.4",
14
+ "@vitest/coverage-v8": "^3.2.4"
15
+ },
16
+ "main": "dist/index.js",
17
+ "module": "dist/index.mjs",
18
+ "types": "dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.mjs",
23
+ "require": "./dist/index.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "check-types": "tsc --noEmit",
28
+ "build": "tsup",
29
+ "lint": "eslint",
30
+ "format": "prettier . --write",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest"
33
+ },
34
+ "sideEffects": false
35
+ }
@@ -0,0 +1,3 @@
1
+ import base from '@stack-dev/prettier-config/base.mjs';
2
+
3
+ export default base;
@@ -0,0 +1,26 @@
1
+ import { EqualityChecker, defaultEqualityChecker } from './have-same-items';
2
+
3
+ export function areObjectsEqual<T>(
4
+ a: Record<string, T>,
5
+ b: Record<string, T>,
6
+ areEqual: EqualityChecker<T> = defaultEqualityChecker,
7
+ ): boolean {
8
+ return (
9
+ areObjectsEqualInOneDirection(a, b, areEqual) ||
10
+ areObjectsEqualInOneDirection(b, a, areEqual)
11
+ );
12
+ }
13
+
14
+ function areObjectsEqualInOneDirection<T>(
15
+ a: Record<string, T>,
16
+ b: Record<string, T>,
17
+ areEqual: EqualityChecker<T>,
18
+ ): boolean {
19
+ for (const key of Object.keys(a)) {
20
+ if (!(key in b) || !areEqual(a[key], b[key])) {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ return true;
26
+ }
@@ -0,0 +1,84 @@
1
+ // TODO: Break this up
2
+ export const TOL = 1e-8;
3
+
4
+ export type EqualityChecker<T> = (t1: T, t2: T, tol?: number) => boolean;
5
+
6
+ export interface Equalable {
7
+ equals(other: unknown, tol?: number): boolean;
8
+ }
9
+
10
+ export function isEqualable(t: unknown): t is Equalable {
11
+ return (
12
+ typeof t === 'object' &&
13
+ t !== null &&
14
+ 'equals' in t &&
15
+ typeof t.equals === 'function'
16
+ );
17
+ }
18
+
19
+ export const defaultEqualityChecker: EqualityChecker<unknown> = (
20
+ t1,
21
+ t2,
22
+ tol = TOL,
23
+ ) => {
24
+ if (isEqualable(t1)) {
25
+ return t1.equals(t2, tol);
26
+ } else {
27
+ return t1 === t2;
28
+ }
29
+ };
30
+
31
+ export function haveSameItems<T>(
32
+ it1: Iterable<T>,
33
+ it2: Iterable<T>,
34
+ check: EqualityChecker<T> = defaultEqualityChecker,
35
+ ): boolean {
36
+ if (bothZeroLength<T>(it1, it2)) {
37
+ return true;
38
+ }
39
+
40
+ if (diffLength<T>(it1, it2)) {
41
+ return false;
42
+ }
43
+
44
+ return haveSameItems_sameLength(it1, it2, check);
45
+ }
46
+
47
+ function haveSameItems_sameLength<T>(
48
+ it1: Iterable<T>,
49
+ it2: Iterable<T>,
50
+ check: EqualityChecker<T>,
51
+ ) {
52
+ const arr1 = [...it1];
53
+ let arr2 = [...it2];
54
+
55
+ for (const item1 of arr1) {
56
+ const i2 = arr2.findIndex((item2) => check(item1, item2));
57
+ if (i2 === -1) {
58
+ return false;
59
+ } else {
60
+ arr2 = remoteAtIndex(arr2, i2);
61
+ }
62
+ }
63
+
64
+ return true;
65
+ }
66
+
67
+ function remoteAtIndex<T>(arr: Array<T>, i2: number): Array<T> {
68
+ const before = arr.slice(0, i2);
69
+ const after = arr.slice(i2 + 1);
70
+
71
+ return [...before, ...after];
72
+ }
73
+
74
+ function diffLength<T>(it1: Iterable<T>, it2: Iterable<T>) {
75
+ return getSize(it1) !== getSize(it2);
76
+ }
77
+
78
+ function bothZeroLength<T>(it1: Iterable<T>, it2: Iterable<T>) {
79
+ return getSize(it1) === 0 && getSize(it2) === 0;
80
+ }
81
+
82
+ function getSize(it: Iterable<unknown>): number {
83
+ return [...it].length;
84
+ }
@@ -0,0 +1,6 @@
1
+ export * from './are-objects-equal';
2
+ export * from './have-same-items';
3
+
4
+ export * from './sort-keys';
5
+
6
+ export * from './snapshot';
@@ -0,0 +1,11 @@
1
+ export type Snapshot = {
2
+ [key: string]: SnapshotValue;
3
+ };
4
+
5
+ export type SnapshotValue =
6
+ | string
7
+ | number
8
+ | boolean
9
+ | undefined
10
+ | Snapshot
11
+ | ReadonlyArray<SnapshotValue>;
@@ -0,0 +1,7 @@
1
+ export function sortKeys<T extends Record<string, unknown>>(
2
+ obj: T,
3
+ comparer: (a: string, b: string) => number,
4
+ ): Record<string, unknown> {
5
+ const sortedEntries = Object.entries(obj).sort(([a], [b]) => comparer(a, b));
6
+ return Object.fromEntries(sortedEntries);
7
+ }
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { areObjectsEqual } from '../are-objects-equal';
4
+
5
+ describe('areObjectsEqual', () => {
6
+ it('Returns true for both empty.', () => {
7
+ expect(areObjectsEqual({}, {})).toBe(true);
8
+ });
9
+
10
+ it('Returns false with different keys.', () => {
11
+ const a = { a: 1, b: 2 };
12
+ const b = { a: 1, c: 3 };
13
+
14
+ expect(areObjectsEqual(a, b)).toBe(false);
15
+ });
16
+
17
+ it('Returns false with different values.', () => {
18
+ const a = { a: 1, b: 2 };
19
+ const b = { b: 3, a: 1 };
20
+
21
+ expect(areObjectsEqual(a, b)).toBe(false);
22
+ });
23
+
24
+ it('Returns true with same values.', () => {
25
+ const a = { a: 1, b: 2 };
26
+ const b = { b: 2, a: 1 };
27
+
28
+ expect(areObjectsEqual(a, b)).toBe(true);
29
+ });
30
+ });
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { haveSameItems } from '../have-same-items';
4
+
5
+ const numsEqual = (n1: number, n2: number) => n1 === n2;
6
+
7
+ describe('haveSameItems', () => {
8
+ it('Returns true for empty.', () => {
9
+ expect(haveSameItems([], [], () => false)).toBe(true);
10
+ });
11
+
12
+ it('Returns false for different sizes', () => {
13
+ expect(haveSameItems([], [1], () => true)).toBe(false);
14
+ expect(haveSameItems([1], [], () => true)).toBe(false);
15
+ });
16
+
17
+ it('Returns true for equal in order.', () => {
18
+ expect(haveSameItems([1, 2, 3], [1, 2, 3], numsEqual)).toBe(true);
19
+ });
20
+
21
+ it('Returns true for same items.', () => {
22
+ expect(haveSameItems([1, 2, 3], [2, 1, 3], numsEqual)).toBe(true);
23
+ });
24
+
25
+ it('Returns false for different items.', () => {
26
+ expect(haveSameItems([1, 2, 0], [2, 1, 3], numsEqual)).toBe(false);
27
+ expect(haveSameItems([1, 1, 1], [2, 1, 1], numsEqual)).toBe(false);
28
+ });
29
+ });
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { areObjectsEqual } from '../are-objects-equal';
4
+ import { sortKeys } from '../sort-keys';
5
+
6
+ describe('sortKeys', () => {
7
+ it('sorts keys alphabetically', () => {
8
+ const input = {
9
+ z: 1,
10
+ a: 2,
11
+ m: 3,
12
+ };
13
+
14
+ const result = sortKeys(input, (a, b) => a.localeCompare(b));
15
+
16
+ expect(Object.keys(result)).toEqual(['a', 'm', 'z']);
17
+ });
18
+
19
+ it('prioritizes certain keys using a custom comparer', () => {
20
+ const input = {
21
+ scripts: {},
22
+ version: '1.0.0',
23
+ name: 'my-package',
24
+ dependencies: {},
25
+ };
26
+
27
+ function comparer(a: string, b: string) {
28
+ return getIndex(a) - getIndex(b);
29
+ }
30
+
31
+ function getIndex(s: string): number {
32
+ switch (s.toLowerCase()) {
33
+ case 'name':
34
+ return 1;
35
+ case 'version':
36
+ return 2;
37
+ case 'scripts':
38
+ return 3;
39
+ case 'dependencies':
40
+ return 4;
41
+ default:
42
+ return 0;
43
+ }
44
+ }
45
+
46
+ const result = sortKeys(input, comparer);
47
+
48
+ expect(Object.keys(result)).toEqual([
49
+ 'name',
50
+ 'version',
51
+ 'scripts',
52
+ 'dependencies',
53
+ ]);
54
+
55
+ expect(areObjectsEqual(input, result)).toBe(true);
56
+ });
57
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@stack-dev/typescript-config/tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist"
5
+ },
6
+ "include": ["src"]
7
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm', 'cjs'], // Tree-shakable ESM + CommonJS for broader support
6
+ dts: true, // Emit type declarations
7
+ sourcemap: true,
8
+ clean: true,
9
+ target: 'esnext',
10
+ outExtension({ format }) {
11
+ return {
12
+ js: format === 'esm' ? '.mjs' : '.js',
13
+ };
14
+ },
15
+ });
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ coverage: {
7
+ provider: 'v8',
8
+ },
9
+ environment: 'node',
10
+ },
11
+ });
@@ -0,0 +1,10 @@
1
+ import base from '@stack-dev/eslint-config/base.mjs';
2
+ import react from '@stack-dev/eslint-config/react.mjs';
3
+
4
+ export default [
5
+ ...base,
6
+ ...react,
7
+ {
8
+ ignores: ['**/dist/**', '**/coverage/**']
9
+ }
10
+ ];
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/esbuild@0.27.2/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/bin/esbuild" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/esbuild@0.27.2/node_modules/esbuild/bin/esbuild" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules/eslint/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules/eslint/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules/eslint/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules/eslint/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/eslint@9.32.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../eslint/bin/eslint.js" "$@"
19
+ else
20
+ exec node "$basedir/../eslint/bin/eslint.js" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules/prettier/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules/prettier/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules/prettier/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules/prettier/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/prettier@3.6.2/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../prettier/bin/prettier.cjs" "$@"
19
+ else
20
+ exec node "$basedir/../prettier/bin/prettier.cjs" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/tsc" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/tsc" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/typescript@5.8.3/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/tsserver" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript/bin/tsserver" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/dist/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/dist/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../tsup/dist/cli-default.js" "$@"
19
+ else
20
+ exec node "$basedir/../tsup/dist/cli-default.js" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/dist/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/dist/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules/tsup/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.8.3_yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../tsup/dist/cli-node.js" "$@"
19
+ else
20
+ exec node "$basedir/../tsup/dist/cli-node.js" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules/vitest/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules/vitest/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/vitest@3.2.4_@types+node@24.0.15_jsdom@25.0.1/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/yaml@2.8.0/node_modules:/home/benmclean/projects/stack-dev/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/bin.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/yaml@2.8.0/node_modules/yaml/bin.mjs" "$@"
21
+ fi