betterddb 0.6.13 → 0.7.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 (66) hide show
  1. package/.github/workflows/npm-publish.yml +33 -0
  2. package/.github/workflows/test.yml +42 -0
  3. package/API_REFERENCE.md +544 -0
  4. package/CONTRIBUTING.md +225 -0
  5. package/LICENCSE +21 -0
  6. package/README.md +59 -50
  7. package/docker-compose.yml +16 -0
  8. package/eslint.config.mjs +29 -0
  9. package/jest.config.js +16 -0
  10. package/package.json +15 -10
  11. package/prettier.config.js +6 -0
  12. package/src/betterddb.ts +267 -0
  13. package/src/builders/batch-get-builder.ts +56 -0
  14. package/src/builders/create-builder.ts +97 -0
  15. package/src/builders/delete-builder.ts +87 -0
  16. package/src/builders/get-builder.ts +78 -0
  17. package/src/builders/index.ts +7 -0
  18. package/src/builders/query-builder.ts +242 -0
  19. package/src/builders/scan-builder.ts +98 -0
  20. package/src/builders/update-builder.ts +344 -0
  21. package/src/index.ts +4 -0
  22. package/src/operator.ts +43 -0
  23. package/src/types/index.ts +1 -0
  24. package/src/types/paginated-result.ts +6 -0
  25. package/test/batch-get.test.ts +122 -0
  26. package/test/create.test.ts +121 -0
  27. package/test/delete.test.ts +93 -0
  28. package/test/get.test.ts +98 -0
  29. package/test/query.test.ts +206 -0
  30. package/test/scan.test.ts +130 -0
  31. package/test/update.test.ts +352 -0
  32. package/test/utils/table-setup.ts +62 -0
  33. package/tsconfig.json +23 -0
  34. package/dist/betterddb.js +0 -164
  35. package/dist/builders/batch-get-builder.js +0 -54
  36. package/dist/builders/create-builder.js +0 -84
  37. package/dist/builders/delete-builder.js +0 -75
  38. package/dist/builders/get-builder.js +0 -76
  39. package/dist/builders/query-builder.js +0 -164
  40. package/dist/builders/scan-builder.js +0 -76
  41. package/dist/builders/update-builder.js +0 -195
  42. package/dist/index.js +0 -17
  43. package/dist/operator.js +0 -31
  44. package/dist/types/betterddb.d.ts +0 -137
  45. package/dist/types/betterddb.d.ts.map +0 -1
  46. package/dist/types/builders/batch-get-builder.d.ts +0 -16
  47. package/dist/types/builders/batch-get-builder.d.ts.map +0 -1
  48. package/dist/types/builders/create-builder.d.ts +0 -12
  49. package/dist/types/builders/create-builder.d.ts.map +0 -1
  50. package/dist/types/builders/delete-builder.d.ts +0 -18
  51. package/dist/types/builders/delete-builder.d.ts.map +0 -1
  52. package/dist/types/builders/get-builder.d.ts +0 -18
  53. package/dist/types/builders/get-builder.d.ts.map +0 -1
  54. package/dist/types/builders/query-builder.d.ts +0 -29
  55. package/dist/types/builders/query-builder.d.ts.map +0 -1
  56. package/dist/types/builders/scan-builder.d.ts +0 -21
  57. package/dist/types/builders/scan-builder.d.ts.map +0 -1
  58. package/dist/types/builders/update-builder.d.ts +0 -36
  59. package/dist/types/builders/update-builder.d.ts.map +0 -1
  60. package/dist/types/index.d.ts +0 -2
  61. package/dist/types/index.d.ts.map +0 -1
  62. package/dist/types/operator.d.ts +0 -3
  63. package/dist/types/operator.d.ts.map +0 -1
  64. package/dist/types/paginated-result.js +0 -2
  65. package/dist/types/types/paginated-result.d.ts +0 -6
  66. package/dist/types/types/paginated-result.d.ts.map +0 -1
@@ -0,0 +1,225 @@
1
+ # Contributing to BetterDDB
2
+
3
+ First off, thank you for considering contributing to BetterDDB! It's people like you that make BetterDDB such a great tool.
4
+
5
+ ## Code of Conduct
6
+
7
+ This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code.
8
+
9
+ ## How Can I Contribute?
10
+
11
+ ### Reporting Bugs
12
+
13
+ Before creating bug reports, please check the issue list as you might find out that you don't need to create one. When you are creating a bug report, please include as many details as possible:
14
+
15
+ - Use a clear and descriptive title
16
+ - Describe the exact steps which reproduce the problem
17
+ - Provide specific examples to demonstrate the steps
18
+ - Describe the behavior you observed after following the steps
19
+ - Explain which behavior you expected to see instead and why
20
+ - Include code samples and error messages if applicable
21
+
22
+ ### Suggesting Enhancements
23
+
24
+ Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, please include:
25
+
26
+ - Use a clear and descriptive title
27
+ - Provide a step-by-step description of the suggested enhancement
28
+ - Provide specific examples to demonstrate the steps
29
+ - Describe the current behavior and explain which behavior you expected to see instead
30
+ - Explain why this enhancement would be useful
31
+
32
+ ### Pull Requests
33
+
34
+ - Fork the repo and create your branch from `main`
35
+ - If you've added code that should be tested, add tests
36
+ - Ensure the test suite passes
37
+ - Make sure your code lints
38
+ - Update the documentation
39
+
40
+ ## Development Setup
41
+
42
+ 1. Fork and clone the repo
43
+ 2. Run `npm install` to install dependencies
44
+ 3. Start LocalStack for DynamoDB testing: `docker-compose up -d`
45
+ 4. Run `npm test` to run the tests
46
+ 5. Create a branch for your changes
47
+
48
+ ### Local Development Environment
49
+
50
+ ```bash
51
+ # Install dependencies
52
+ npm install
53
+
54
+ # Start LocalStack (required for tests)
55
+ docker-compose up -d
56
+
57
+ # Run tests
58
+ npm test
59
+
60
+ # Run linter
61
+ npm run lint
62
+
63
+ # Build the project
64
+ npm run build
65
+ ```
66
+
67
+ ## Testing
68
+
69
+ We use Jest for testing against a local DynamoDB instance provided by LocalStack. All tests can be found in the `test/` directory.
70
+
71
+ ### Test Directory Structure
72
+
73
+ ```
74
+ test/
75
+ ├── create.test.ts # Tests for create operations
76
+ ├── get.test.ts # Tests for get operations
77
+ ├── update.test.ts # Tests for update operations
78
+ ├── delete.test.ts # Tests for delete operations
79
+ ├── query.test.ts # Tests for query operations
80
+ ├── scan.test.ts # Tests for scan operations
81
+ ├── batch-get.test.ts # Tests for batch get operations
82
+ └── utils/
83
+ └── table-setup.ts # Utilities for setting up test tables
84
+ ```
85
+
86
+ ### Writing Tests
87
+
88
+ Each test file focuses on a specific aspect of the library. Tests should follow this pattern:
89
+
90
+ 1. **Setup**: Define schema, table configuration, and BetterDDB instance
91
+ 2. **Initialize**: Create the test table in LocalStack before tests run
92
+ 3. **Test**: Write test cases for specific functionality
93
+ 4. **Cleanup**: Delete the test table after tests complete
94
+
95
+ Here's an example of a basic test structure:
96
+
97
+ ```typescript
98
+ import { z } from "zod";
99
+ import { BetterDDB } from "../src/betterddb";
100
+ import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
101
+ import { DynamoDB } from "@aws-sdk/client-dynamodb";
102
+ import { createTestTable, deleteTestTable } from "./utils/table-setup";
103
+
104
+ // Constants for test configuration
105
+ const TEST_TABLE = "my-test-table";
106
+ const ENDPOINT = "http://localhost:4566";
107
+ const REGION = "us-east-1";
108
+
109
+ // Define schema and key configuration
110
+ const MySchema = z.object({
111
+ id: z.string(),
112
+ name: z.string(),
113
+ });
114
+
115
+ // Create DynamoDB client
116
+ const client = DynamoDBDocumentClient.from(
117
+ new DynamoDB({
118
+ region: REGION,
119
+ endpoint: ENDPOINT,
120
+ }),
121
+ );
122
+
123
+ // Create BetterDDB instance
124
+ const myDdb = new BetterDDB({
125
+ schema: MySchema,
126
+ tableName: TEST_TABLE,
127
+ keys: {
128
+ primary: {
129
+ name: "pk",
130
+ definition: { build: (raw) => `ITEM#${raw.id}` },
131
+ },
132
+ sort: {
133
+ name: "sk",
134
+ definition: { build: (raw) => `ITEM` },
135
+ },
136
+ },
137
+ client,
138
+ timestamps: true,
139
+ });
140
+
141
+ // Setup and teardown
142
+ beforeAll(async () => {
143
+ await createTestTable(TEST_TABLE, KEY_SCHEMA, ATTRIBUTE_DEFINITIONS, GSIS);
144
+ });
145
+
146
+ afterAll(async () => {
147
+ await deleteTestTable(TEST_TABLE);
148
+ });
149
+
150
+ // Test cases
151
+ describe("My Feature", () => {
152
+ it("should do something specific", async () => {
153
+ // Test implementation
154
+ const result = await myDdb.create({ id: "123", name: "Test" }).execute();
155
+ expect(result.id).toBe("123");
156
+ });
157
+ });
158
+ ```
159
+
160
+ ### Testing Utilities
161
+
162
+ The `test/utils/table-setup.ts` file provides utilities for creating and deleting DynamoDB tables for testing:
163
+
164
+ - **createTestTable**: Creates a DynamoDB table in LocalStack with the specified configuration
165
+ - **deleteTestTable**: Deletes a DynamoDB table from LocalStack
166
+
167
+ ### Testing Best Practices
168
+
169
+ 1. **Isolated Tests**: Each test should be independent and not rely on other tests
170
+ 2. **Clean up after tests**: Always delete created resources to avoid interference
171
+ 3. **Test error cases**: Include tests for failure scenarios, not just success
172
+ 4. **Use constants**: Define table names, key names, etc. as constants
173
+ 5. **Test both simple and complex scenarios**: Cover the full range of functionality
174
+ 6. **Add tests for new features**: Any new functionality should have corresponding tests
175
+
176
+ ### Testing against LocalStack
177
+
178
+ Tests run against a LocalStack instance, which provides a local DynamoDB implementation. To use this:
179
+
180
+ 1. Ensure Docker is installed and running
181
+ 2. Start LocalStack with `docker-compose up -d`
182
+ 3. Run tests with `npm test`
183
+
184
+ The `docker-compose.yml` file in the repository configures the LocalStack environment.
185
+
186
+ ## Style Guide
187
+
188
+ - We use ESLint and Prettier for code formatting
189
+ - TypeScript is required for all new code
190
+ - Follow the existing code style
191
+ - Write descriptive commit messages
192
+ - Add tests for new features
193
+ - Update documentation for changes
194
+
195
+ ## Project Structure
196
+
197
+ ```
198
+ src/
199
+ ├── builders/ # Query builders
200
+ ├── errors/ # Custom error types
201
+ ├── types/ # TypeScript type definitions
202
+ ├── betterddb.ts # Main class
203
+ └── index.ts # Public API
204
+ test/
205
+ ├── *.test.ts # Test files
206
+ └── utils/ # Test utilities
207
+ ```
208
+
209
+ ## Documentation
210
+
211
+ - Keep README.md updated
212
+ - Document new features
213
+ - Keep code comments clear and relevant
214
+ - Update TypeScript types
215
+ - Update API_REFERENCE.md with new functionality
216
+
217
+ ## Community
218
+
219
+ - Join our [Discussions](https://github.com/ryanrawlingswang/betterddb/discussions)
220
+
221
+ ## Questions?
222
+
223
+ Feel free to open an issue or join our discussions if you have any questions.
224
+
225
+ Thank you for contributing! 🎉
package/LICENCSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ryan Rawlings Wang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -23,9 +23,9 @@ npm install betterddb
23
23
  ## Quick Start
24
24
 
25
25
  ```typescript
26
- import { BetterDDB } from 'betterddb';
27
- import { z } from 'zod';
28
- import { DynamoDBDocumentClient, DynamoDB } from '@aws-sdk/lib-dynamodb';
26
+ import { BetterDDB } from "betterddb";
27
+ import { z } from "zod";
28
+ import { DynamoDBDocumentClient, DynamoDB } from "@aws-sdk/lib-dynamodb";
29
29
 
30
30
  // 1. Define your schema with Zod
31
31
  const UserSchema = z.object({
@@ -38,37 +38,39 @@ const UserSchema = z.object({
38
38
  type User = z.infer<typeof UserSchema>;
39
39
 
40
40
  // 2. Initialize DynamoDB client
41
- const client = DynamoDBDocumentClient.from(new DynamoDB({
42
- region: 'us-east-1',
43
- }));
41
+ const client = DynamoDBDocumentClient.from(
42
+ new DynamoDB({
43
+ region: "us-east-1",
44
+ }),
45
+ );
44
46
 
45
47
  // 3. Create your BetterDDB instance
46
48
  const userDdb = new BetterDDB<User>({
47
49
  schema: UserSchema,
48
- tableName: 'Users',
49
- entityType: 'USER',
50
+ tableName: "Users",
51
+ entityType: "USER",
50
52
  keys: {
51
- primary: {
52
- name: 'pk',
53
- definition: { build: (raw) => `USER#${raw.id}` }
53
+ primary: {
54
+ name: "pk",
55
+ definition: { build: (raw) => `USER#${raw.id}` },
54
56
  },
55
- sort: {
56
- name: 'sk',
57
- definition: { build: (raw) => `EMAIL#${raw.email}` }
57
+ sort: {
58
+ name: "sk",
59
+ definition: { build: (raw) => `EMAIL#${raw.email}` },
58
60
  },
59
61
  gsis: {
60
62
  EmailIndex: {
61
- name: 'EmailIndex',
62
- primary: {
63
- name: 'gsi1pk',
64
- definition: { build: (raw) => `USER#${raw.email}` }
63
+ name: "EmailIndex",
64
+ primary: {
65
+ name: "gsi1pk",
66
+ definition: { build: (raw) => `USER#${raw.email}` },
67
+ },
68
+ sort: {
69
+ name: "gsi1sk",
70
+ definition: { build: (raw) => `USER#${raw.email}` },
65
71
  },
66
- sort: {
67
- name: 'gsi1sk',
68
- definition: { build: (raw) => `USER#${raw.email}` }
69
- }
70
- }
71
- }
72
+ },
73
+ },
72
74
  },
73
75
  client,
74
76
  timestamps: true,
@@ -77,22 +79,26 @@ const userDdb = new BetterDDB<User>({
77
79
  // 4. Use the fluent API for operations
78
80
  async function example() {
79
81
  // Create with automatic validation
80
- const user = await userDdb.create({
81
- id: 'user-123',
82
- name: 'Alice',
83
- email: 'alice@example.com'
84
- }).execute();
82
+ const user = await userDdb
83
+ .create({
84
+ id: "user-123",
85
+ name: "Alice",
86
+ email: "alice@example.com",
87
+ })
88
+ .execute();
85
89
 
86
90
  // Query with type-safe filters
87
- const results = await userDdb.query({ email: 'alice@example.com' })
88
- .usingIndex('EmailIndex')
89
- .filter('name', 'begins_with', 'A')
91
+ const results = await userDdb
92
+ .query({ email: "alice@example.com" })
93
+ .usingIndex("EmailIndex")
94
+ .filter("name", "begins_with", "A")
90
95
  .limitResults(10)
91
96
  .execute();
92
97
 
93
98
  // Update with automatic timestamp handling
94
- const updated = await userDdb.update({ id: 'user-123' })
95
- .set({ name: 'Alice B.' })
99
+ const updated = await userDdb
100
+ .update({ id: "user-123" })
101
+ .set({ name: "Alice B." })
96
102
  .execute();
97
103
  }
98
104
  ```
@@ -104,11 +110,13 @@ async function example() {
104
110
  BetterDDB uses Zod for both runtime validation and TypeScript type inference:
105
111
 
106
112
  ```typescript
107
- const Schema = z.object({
108
- id: z.string(),
109
- name: z.string(),
110
- email: z.string().email(),
111
- }).passthrough(); // Allow computed fields
113
+ const Schema = z
114
+ .object({
115
+ id: z.string(),
116
+ name: z.string(),
117
+ email: z.string().email(),
118
+ })
119
+ .passthrough(); // Allow computed fields
112
120
 
113
121
  type Entity = z.infer<typeof Schema>; // TypeScript type inference
114
122
  ```
@@ -121,14 +129,14 @@ Define how your keys should be computed from your entity:
121
129
  const ddb = new BetterDDB<User>({
122
130
  keys: {
123
131
  primary: {
124
- name: 'pk',
125
- definition: { build: (raw) => `USER#${raw.id}` }
132
+ name: "pk",
133
+ definition: { build: (raw) => `USER#${raw.id}` },
126
134
  },
127
135
  sort: {
128
- name: 'sk',
129
- definition: { build: (raw) => `TYPE#${raw.type}` }
130
- }
131
- }
136
+ name: "sk",
137
+ definition: { build: (raw) => `TYPE#${raw.type}` },
138
+ },
139
+ },
132
140
  });
133
141
  ```
134
142
 
@@ -137,10 +145,11 @@ const ddb = new BetterDDB<User>({
137
145
  Fluent API for building type-safe queries:
138
146
 
139
147
  ```typescript
140
- const results = await ddb.query({ id: 'user-123' })
141
- .usingIndex('EmailIndex')
142
- .where('begins_with', { email: 'alice' })
143
- .filter('name', 'contains', 'Smith')
148
+ const results = await ddb
149
+ .query({ id: "user-123" })
150
+ .usingIndex("EmailIndex")
151
+ .where("begins_with", { email: "alice" })
152
+ .filter("name", "contains", "Smith")
144
153
  .limitResults(10)
145
154
  .execute();
146
155
  ```
@@ -164,4 +173,4 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
164
173
 
165
174
  ## License
166
175
 
167
- MIT © Ryan Krumholz
176
+ MIT © Ryan Rawlings Wang
@@ -0,0 +1,16 @@
1
+ version: "3.8"
2
+ services:
3
+ betterddb-localstack:
4
+ image: localstack/localstack:latest
5
+ container_name: betterddb-localstack
6
+ ports:
7
+ - "4566:4566" # Main edge port
8
+ - "4571:4571"
9
+ environment:
10
+ - SERVICES=dynamodb
11
+ - DEFAULT_REGION=us-east-1
12
+ - DATA_DIR=/tmp/localstack_data
13
+ - HOST_TMP_FOLDER=${TMPDIR:-/tmp}/localstack
14
+ - LOCALSTACK_UI=1
15
+ volumes:
16
+ - "./localstack-tmp:/tmp/localstack_data"
@@ -0,0 +1,29 @@
1
+ import js from '@eslint/js';
2
+ import tseslint from '@typescript-eslint/eslint-plugin';
3
+ import tsparser from '@typescript-eslint/parser';
4
+ import prettier from 'eslint-plugin-prettier';
5
+
6
+ export default [
7
+ js.configs.recommended,
8
+ {
9
+ files: ['**/*.ts'],
10
+ languageOptions: {
11
+ parser: tsparser,
12
+ parserOptions: {
13
+ ecmaVersion: 'latest',
14
+ sourceType: 'module',
15
+ },
16
+ },
17
+ plugins: {
18
+ '@typescript-eslint': tseslint,
19
+ prettier: prettier,
20
+ },
21
+ rules: {
22
+ 'prettier/prettier': 'error',
23
+ // Basic TypeScript rules
24
+ '@typescript-eslint/no-unused-vars': 'warn',
25
+ '@typescript-eslint/no-explicit-any': 'warn',
26
+ '@typescript-eslint/no-non-null-assertion': 'warn',
27
+ },
28
+ },
29
+ ];
package/jest.config.js ADDED
@@ -0,0 +1,16 @@
1
+ const config = {
2
+ testEnvironment: "node",
3
+ roots: ["<rootDir>/test/"],
4
+ testMatch: ["**/*.test.ts"],
5
+ transform: {
6
+ "^.+\\.(ts|tsx|js|jsx)$": "ts-jest",
7
+ },
8
+ moduleNameMapper: {
9
+ "^@/(.*)$": "<rootDir>/src/$1",
10
+ "^~/(.*)$": "<rootDir>/src/$1",
11
+ },
12
+ extensionsToTreatAsEsm: [".ts", ".tsx"],
13
+ moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
14
+ };
15
+
16
+ export default config;
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "betterddb",
3
- "version": "0.6.13",
3
+ "version": "0.7.0",
4
4
  "description": "A definition-based DynamoDB wrapper library that provides a schema-driven and fully typesafe DAL.",
5
- "main": "dist/index.js",
6
- "types": "dist/types/index.d.ts",
7
- "files": [
8
- "dist/**/*"
9
- ],
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
10
14
  "scripts": {
11
- "prepublishOnly": "npm run build",
15
+ "build": "tsc",
12
16
  "docker:up": "docker-compose up -d",
13
17
  "docker:down": "docker-compose down",
14
18
  "test": "npm run docker:up && jest && npm run docker:down",
@@ -17,8 +21,7 @@
17
21
  "format": "prettier --write 'src/**/*.ts'",
18
22
  "lint": "eslint src/**/*.ts",
19
23
  "clean": "del-cli ./dist",
20
- "build": "npm run clean && tsc -p ./tsconfig.json",
21
- "prepack": "npm run build"
24
+ "typecheck": "tsc --noEmit"
22
25
  },
23
26
  "keywords": [
24
27
  "dynamodb",
@@ -40,9 +43,11 @@
40
43
  "zod": "^3.24.2"
41
44
  },
42
45
  "devDependencies": {
46
+ "@eslint/js": "^9.11.1",
43
47
  "@types/jest": "^29.5.14",
44
48
  "@types/node": "^22.13.5",
45
49
  "@typescript-eslint/eslint-plugin": "^8.24.1",
50
+ "@typescript-eslint/parser": "^8.24.1",
46
51
  "del-cli": "^6.0.0",
47
52
  "eslint": "^8.57.1",
48
53
  "eslint-config-prettier": "^9.1.0",
@@ -50,6 +55,6 @@
50
55
  "jest": "^29.7.0",
51
56
  "prettier": "^3.3.3",
52
57
  "ts-jest": "^29.2.5",
53
- "typescript": "^4.9.5"
58
+ "typescript": "latest"
54
59
  }
55
60
  }
@@ -0,0 +1,6 @@
1
+ /** @type {import('prettier').Config} */
2
+ const config = {
3
+ tabWidth: 2,
4
+ };
5
+
6
+ export default config;