airyhooks 0.1.0-beta.0 → 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.
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # airyhooks
2
+
3
+ Add production-ready React hooks directly to your project—no package installation required.
4
+
5
+ airyhooks is a CLI tool that lets you add battle-tested, TypeScript-first React hooks directly to your codebase. Instead of installing a package, you copy exactly what you need. This gives you complete control: modify hooks for your use case, avoid dependency bloat, and eliminate version conflicts.
6
+
7
+ ```bash
8
+ pnpm dlx airyhooks@latest add useDebounce
9
+ ```
10
+
11
+ ## Why airyhooks?
12
+
13
+ - **Zero Dependencies**: Hooks only depend on React—nothing else
14
+ - **Full Ownership**: Code lives in your repo; customize freely
15
+ - **TypeScript Native**: Complete type safety with generics
16
+ - **Battle-Tested**: 50+ tests, 94%+ coverage
17
+ - **One Command**: Add hooks instantly with the CLI
18
+
19
+ ## 🚀 Quick Start
20
+
21
+ ### 1. Initialize
22
+
23
+ Create the configuration file and set your hooks directory:
24
+
25
+ ```bash
26
+ pnpm dlx airyhooks@latest init
27
+ ```
28
+
29
+ This creates `airyhooks.json` in your project root and prompts you for the hooks directory path (default: `./hooks`).
30
+
31
+ ### 2. Add a Hook
32
+
33
+ Add any hook to your project:
34
+
35
+ ```bash
36
+ pnpm dlx airyhooks@latest add useDebounce
37
+ ```
38
+
39
+ This creates the following structure:
40
+
41
+ ```
42
+ hooks/
43
+ ├── useDebounce/
44
+ │ ├── useDebounce.ts
45
+ │ └── index.ts
46
+ ```
47
+
48
+ ### 3. Use in Your Code
49
+
50
+ Import and use the hook in your components:
51
+
52
+ ```tsx
53
+ import { useDebounce } from "./hooks/useDebounce";
54
+
55
+ export function SearchComponent() {
56
+ const [value, setValue] = useState("");
57
+ const debouncedValue = useDebounce(value, 500);
58
+
59
+ return (
60
+ <div>
61
+ <input value={value} onChange={(e) => setValue(e.target.value)} />
62
+ <p>Searching for: {debouncedValue}</p>
63
+ </div>
64
+ );
65
+ }
66
+ ```
67
+
68
+ ## 📖 Commands
69
+
70
+ ### `airyhooks init`
71
+
72
+ Initialize airyhooks in your project. Creates `airyhooks.json` configuration file and prompts for your hooks directory path.
73
+
74
+ ```bash
75
+ pnpm dlx airyhooks@latest init
76
+ # or
77
+ npx airyhooks@latest init
78
+ ```
79
+
80
+ ### `airyhooks add <hook-name>`
81
+
82
+ Add a specific hook to your project. Creates the hook directory with TypeScript files.
83
+
84
+ ```bash
85
+ pnpm dlx airyhooks@latest add useDebounce
86
+ ```
87
+
88
+ ### `airyhooks list`
89
+
90
+ List all available hooks with descriptions.
91
+
92
+ ```bash
93
+ pnpm dlx airyhooks@latest list
94
+ ```
95
+
96
+ ## 📚 Available Hooks
97
+
98
+ | Hook | Description |
99
+ | ------------------- | ------------------------------------------------------- |
100
+ | `useDebounce` | Debounce a value with a specified delay |
101
+ | `useThrottle` | Throttle a value to update at most once per interval |
102
+ | `useLocalStorage` | Sync state with localStorage |
103
+ | `useSessionStorage` | Sync state with sessionStorage |
104
+ | `usePrevious` | Track previous state or props value |
105
+ | `useToggle` | Toggle a boolean value with convenient handlers |
106
+ | `useBoolean` | Boolean state with setTrue, setFalse, and toggle |
107
+ | `useMount` | Call a callback on component mount |
108
+ | `useUnmount` | Call a callback on component unmount |
109
+ | `useInterval` | Call a callback at specified intervals |
110
+ | `useTimeout` | Call a callback after a timeout |
111
+ | `useClickAway` | Detect clicks outside of an element |
112
+ | `useWindowSize` | Track window dimensions |
113
+ | `useCounter` | Manage numeric state with increment/decrement/reset/set |
114
+ | `useHover` | Track mouse hover state on elements |
115
+ | `useKeyPress` | Detect specific keyboard key presses |
116
+ | `useMedia` | React to CSS media query changes |
117
+ | `useScroll` | Track scroll position of element or window |
118
+
119
+ ## 💡 Usage Example
120
+
121
+ Here's a complete example using `useDebounce` for a search input:
122
+
123
+ ```tsx
124
+ import { useState } from "react";
125
+ import { useDebounce } from "./hooks/useDebounce";
126
+
127
+ export function App() {
128
+ const [input, setInput] = useState("");
129
+ const debouncedInput = useDebounce(input, 1000);
130
+
131
+ return (
132
+ <div>
133
+ <input
134
+ value={input}
135
+ onChange={(e) => setInput(e.target.value)}
136
+ placeholder="Type something..."
137
+ />
138
+ <p>You typed: {debouncedInput}</p>
139
+ </div>
140
+ );
141
+ }
142
+ ```
143
+
144
+ ## ⚙️ Configuration
145
+
146
+ The `airyhooks.json` file stores your configuration:
147
+
148
+ ```json
149
+ {
150
+ "hooksPath": "./hooks"
151
+ }
152
+ ```
153
+
154
+ You can manually edit this file to change the hooks directory path.
155
+
156
+ ## 📦 Package Managers
157
+
158
+ airyhooks works with all major package managers:
159
+
160
+ ```bash
161
+ # pnpm
162
+ pnpm dlx airyhooks@latest add useDebounce
163
+
164
+ # npm
165
+ npx airyhooks@latest add useDebounce
166
+
167
+ # yarn
168
+ yarn dlx airyhooks@latest add useDebounce
169
+
170
+ # bun
171
+ bunx airyhooks@latest add useDebounce
172
+ ```
173
+
174
+ ## 📄 License
175
+
176
+ MIT
177
+
178
+ ---
179
+
180
+ **Ready to use?** Run `pnpm dlx airyhooks@latest init` to get started!
@@ -0,0 +1,2 @@
1
+ export declare function add(hookName: string): Promise<void>;
2
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1,2 @@
1
+ export declare function init(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1,2 @@
1
+ export declare function list(): void;
2
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
File without changes
@@ -0,0 +1,2 @@
1
+ export declare function getHookTemplate(hookName: string): string;
2
+ //# sourceMappingURL=get-hook-template.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-hook-template.d.ts","sourceRoot":"","sources":["../../src/utils/get-hook-template.ts"],"names":[],"mappings":"AAolCA,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQxD"}
1
+ {"version":3,"file":"get-hook-template.d.ts","sourceRoot":"","sources":["../../src/utils/get-hook-template.ts"],"names":[],"mappings":"AAqkCA,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQxD"}
@@ -130,15 +130,13 @@ export function useClickAway<T extends HTMLElement>(
130
130
  * </>
131
131
  * );
132
132
  */
133
- export function useCounter(
134
- initialValue = 0,
135
- ): [
133
+ export function useCounter(initialValue = 0): [
136
134
  number,
137
135
  {
138
- increment: (amount?: number) => void;
139
136
  decrement: (amount?: number) => void;
137
+ increment: (amount?: number) => void;
140
138
  reset: () => void;
141
- set: (value: number | ((prev: number) => number)) => void;
139
+ set: (value: ((prev: number) => number) | number) => void;
142
140
  },
143
141
  ] {
144
142
  const [count, setCount] = useState<number>(initialValue);
@@ -155,15 +153,15 @@ export function useCounter(
155
153
  setCount(initialValue);
156
154
  }, [initialValue]);
157
155
 
158
- const set = useCallback((value: number | ((prev: number) => number)) => {
156
+ const set = useCallback((value: ((prev: number) => number) | number) => {
159
157
  setCount(value);
160
158
  }, []);
161
159
 
162
160
  return [
163
161
  count,
164
162
  {
165
- increment,
166
163
  decrement,
164
+ increment,
167
165
  reset,
168
166
  set,
169
167
  },
@@ -242,7 +240,7 @@ export function useHover<T extends HTMLElement = HTMLElement>(): [
242
240
 
243
241
  // Attach event listeners to the ref
244
242
  const setRef = useCallback(
245
- (element: T | null) => {
243
+ (element: null | T) => {
246
244
  if (ref.current) {
247
245
  ref.current.removeEventListener("mouseenter", handleMouseEnter);
248
246
  ref.current.removeEventListener("mouseleave", handleMouseLeave);
@@ -253,7 +251,7 @@ export function useHover<T extends HTMLElement = HTMLElement>(): [
253
251
  element.addEventListener("mouseleave", handleMouseLeave);
254
252
  }
255
253
 
256
- (ref as React.MutableRefObject<T | null>).current = element;
254
+ ref.current = element;
257
255
  },
258
256
  [handleMouseEnter, handleMouseLeave],
259
257
  );
@@ -262,11 +260,10 @@ export function useHover<T extends HTMLElement = HTMLElement>(): [
262
260
  return [
263
261
  isHovered,
264
262
  {
265
- current: ref.current,
266
263
  get current() {
267
264
  return ref.current;
268
265
  },
269
- set current(element: T | null) {
266
+ set current(element: null | T) {
270
267
  setRef(element);
271
268
  },
272
269
  } as React.RefObject<T>,
@@ -477,7 +474,7 @@ export function useMedia(query: string): boolean {
477
474
  useEffect(() => {
478
475
  // Check if window is defined (SSR safety)
479
476
  if (typeof window === "undefined") {
480
- return;
477
+ return undefined;
481
478
  }
482
479
 
483
480
  try {
@@ -492,21 +489,13 @@ export function useMedia(query: string): boolean {
492
489
  };
493
490
 
494
491
  // Modern browsers use addEventListener
495
- if (mediaQueryList.addEventListener) {
496
- mediaQueryList.addEventListener("change", handleChange);
497
- return () => {
498
- mediaQueryList.removeEventListener("change", handleChange);
499
- };
500
- } else {
501
- // Fallback for older browsers
502
- mediaQueryList.addListener(handleChange);
503
- return () => {
504
- mediaQueryList.removeListener(handleChange);
505
- };
506
- }
492
+ mediaQueryList.addEventListener("change", handleChange);
493
+ return () => {
494
+ mediaQueryList.removeEventListener("change", handleChange);
495
+ };
507
496
  } catch (error) {
508
497
  console.warn(\`Invalid media query: "\${query}"\`, error);
509
- return;
498
+ return undefined;
510
499
  }
511
500
  }, [query]);
512
501
 
@@ -604,10 +593,9 @@ interface ScrollPosition {
604
593
  * return <div ref={ref}>Content</div>;
605
594
  */
606
595
  export function useScroll(
607
- ref?: React.RefObject<HTMLElement>,
596
+ ref?: React.RefObject<HTMLElement | null>,
608
597
  ): ScrollPosition {
609
598
  const [scroll, setScroll] = useState<ScrollPosition>({ x: 0, y: 0 });
610
- const internalRef = useRef<HTMLElement | null>(null);
611
599
 
612
600
  const handleScroll = useCallback(() => {
613
601
  if (ref?.current) {
@@ -660,16 +648,15 @@ export function useScroll(
660
648
  * style={{ height: "200px", overflow: "auto" }}
661
649
  * >
662
650
  * <p>Scroll position: X: {scroll.x}, Y: {scroll.y}</p>
663
- * {/* long content */}
664
651
  * </div>
665
652
  * );
666
653
  */
667
654
  export function useScrollElement<T extends HTMLElement = HTMLElement>(): [
668
- React.RefObject<T>,
655
+ React.RefObject<null | T>,
669
656
  ScrollPosition,
670
657
  ] {
671
658
  const ref = useRef<T>(null);
672
- const scroll = useScroll(ref);
659
+ const scroll = useScroll(ref as React.RefObject<HTMLElement | null>);
673
660
 
674
661
  return [ref, scroll];
675
662
  }
@@ -697,10 +684,9 @@ interface ScrollPosition {
697
684
  * return <div ref={ref}>Content</div>;
698
685
  */
699
686
  export function useScroll(
700
- ref?: React.RefObject<HTMLElement>,
687
+ ref?: React.RefObject<HTMLElement | null>,
701
688
  ): ScrollPosition {
702
689
  const [scroll, setScroll] = useState<ScrollPosition>({ x: 0, y: 0 });
703
- const internalRef = useRef<HTMLElement | null>(null);
704
690
 
705
691
  const handleScroll = useCallback(() => {
706
692
  if (ref?.current) {
@@ -753,16 +739,15 @@ export function useScroll(
753
739
  * style={{ height: "200px", overflow: "auto" }}
754
740
  * >
755
741
  * <p>Scroll position: X: {scroll.x}, Y: {scroll.y}</p>
756
- * {/* long content */}
757
742
  * </div>
758
743
  * );
759
744
  */
760
745
  export function useScrollElement<T extends HTMLElement = HTMLElement>(): [
761
- React.RefObject<T>,
746
+ React.RefObject<null | T>,
762
747
  ScrollPosition,
763
748
  ] {
764
749
  const ref = useRef<T>(null);
765
- const scroll = useScroll(ref);
750
+ const scroll = useScroll(ref as React.RefObject<HTMLElement | null>);
766
751
 
767
752
  return [ref, scroll];
768
753
  }
@@ -1 +1 @@
1
- {"version":3,"file":"get-hook-template.js","sourceRoot":"","sources":["../../src/utils/get-hook-template.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,+DAA+D;AAC/D,uCAAuC;AAEvC,MAAM,SAAS,GAA2B;IACxC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEb;IAEC,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCf;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Db;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCd;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEX;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cd;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Cd;IAEC,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuFlB;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DX;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCX;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBd;IAEC,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FZ;IAEC,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FnB;IAEC,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEpB;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cd;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cb;IAEC,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEZ;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCb;IAEC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8ChB;CACA,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAErC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,aAAa,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"get-hook-template.js","sourceRoot":"","sources":["../../src/utils/get-hook-template.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,+DAA+D;AAC/D,uCAAuC;AAEvC,MAAM,SAAS,GAA2B;IACxC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEb;IAEC,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCf;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Db;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCd;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEX;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cd;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Cd;IAEC,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuFlB;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDX;IAEC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCX;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBd;IAEC,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0FZ;IAEC,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0FnB;IAEC,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEpB;IAEC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cd;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Cb;IAEC,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEZ;IAEC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCb;IAEC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8ChB;CACA,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAErC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,aAAa,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,21 +1,23 @@
1
1
  {
2
2
  "name": "airyhooks",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0",
4
4
  "description": "CLI to add React hooks to your project",
5
5
  "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/leifarriens/airyhooks.git",
12
+ "directory": "packages/cli"
13
+ },
6
14
  "bin": {
7
15
  "airyhooks": "./dist/index.js"
8
16
  },
9
17
  "files": [
10
- "dist"
18
+ "dist",
19
+ "README.md"
11
20
  ],
12
- "scripts": {
13
- "build": "tsc",
14
- "dev": "tsc --watch",
15
- "typecheck": "tsc --noEmit",
16
- "lint": "eslint .",
17
- "prepublishOnly": "pnpm build"
18
- },
19
21
  "dependencies": {
20
22
  "commander": "^12.1.0",
21
23
  "fs-extra": "^11.2.0",
@@ -23,17 +25,23 @@
23
25
  "prompts": "^2.4.2"
24
26
  },
25
27
  "devDependencies": {
26
- "@airyhooks/eslint-config": "workspace:*",
27
- "@airyhooks/tsconfig": "workspace:*",
28
28
  "@types/fs-extra": "^11.0.4",
29
29
  "@types/prompts": "^2.4.9",
30
30
  "eslint": "^9.38.0",
31
- "typescript": "^5.9.3"
31
+ "typescript": "^5.9.3",
32
+ "@airyhooks/eslint-config": "0.1.0",
33
+ "@airyhooks/tsconfig": "0.1.0"
32
34
  },
33
35
  "keywords": [
34
36
  "react",
35
37
  "hooks",
36
38
  "cli"
37
39
  ],
38
- "license": "MIT"
39
- }
40
+ "license": "MIT",
41
+ "scripts": {
42
+ "build": "tsc",
43
+ "dev": "tsc --watch",
44
+ "typecheck": "tsc --noEmit",
45
+ "lint": "eslint ."
46
+ }
47
+ }