@nlabs/lex 1.49.4 → 1.50.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 (55) hide show
  1. package/.swcrc +35 -0
  2. package/README.md +43 -59
  3. package/__mocks__/chalk.js +19 -17
  4. package/config.json +32 -8
  5. package/examples/lex.config.js +110 -10
  6. package/index.cjs +1 -5
  7. package/lex.config.js +34 -7
  8. package/lib/Button.stories.js +99 -0
  9. package/lib/LexConfig.d.ts +60 -22
  10. package/lib/LexConfig.js +285 -244
  11. package/lib/commands/ai/ai.js +287 -288
  12. package/lib/commands/ai/index.js +8 -7
  13. package/lib/commands/build/build.d.ts +2 -2
  14. package/lib/commands/build/build.js +349 -458
  15. package/lib/commands/clean/clean.js +45 -33
  16. package/lib/commands/compile/compile.js +214 -227
  17. package/lib/commands/config/config.js +46 -42
  18. package/lib/commands/copy/copy.js +36 -35
  19. package/lib/commands/create/create.js +200 -121
  20. package/lib/commands/dev/dev.d.ts +2 -0
  21. package/lib/commands/dev/dev.js +259 -263
  22. package/lib/commands/init/init.js +108 -88
  23. package/lib/commands/link/link.js +18 -14
  24. package/lib/commands/lint/lint.js +735 -742
  25. package/lib/commands/migrate/migrate.js +49 -36
  26. package/lib/commands/publish/publish.js +116 -96
  27. package/lib/commands/serverless/serverless.js +611 -585
  28. package/lib/commands/storybook/storybook.js +242 -238
  29. package/lib/commands/test/test.d.ts +1 -1
  30. package/lib/commands/test/test.js +382 -394
  31. package/lib/commands/update/update.js +141 -120
  32. package/lib/commands/upgrade/upgrade.js +51 -44
  33. package/lib/commands/versions/versions.d.ts +1 -1
  34. package/lib/commands/versions/versions.js +36 -38
  35. package/lib/create/changelog.js +136 -125
  36. package/lib/index.js +40 -38
  37. package/lib/lex.js +95 -68
  38. package/lib/storybook/index.js +6 -1
  39. package/lib/test-react/index.js +7 -84
  40. package/lib/types.d.ts +1 -1
  41. package/lib/types.js +7 -1
  42. package/lib/utils/aiService.js +240 -227
  43. package/lib/utils/app.js +274 -273
  44. package/lib/utils/deepMerge.js +37 -23
  45. package/lib/utils/file.js +218 -215
  46. package/lib/utils/log.js +29 -27
  47. package/lib/utils/reactShim.js +7 -85
  48. package/lib/utils/translations.js +91 -65
  49. package/package.json +63 -64
  50. package/templates/typescript/DataLayer.js.txt +218 -0
  51. package/templates/typescript/DataLayer.test.js.txt +268 -0
  52. package/templates/typescript/DataLayer.test.ts.txt +269 -0
  53. package/templates/typescript/DataLayer.ts.txt +227 -0
  54. package/webpack.config.js +53 -26
  55. package/lib/commands/lint/autofix.d.ts +0 -2
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */
5
+
6
+ class DataLayer {
7
+ constructor(options = {}) {
8
+ this.options = {
9
+ tableName: process.env.TABLE_NAME || 'default-table',
10
+ region: process.env.AWS_REGION || 'us-east-1',
11
+ endpoint: process.env.DYNAMODB_ENDPOINT,
12
+ ...options
13
+ };
14
+ }
15
+
16
+ /**
17
+ * Get a single item by ID
18
+ */
19
+ async getItem(id) {
20
+ try {
21
+ // TODO: Implement DynamoDB getItem logic
22
+ console.log(`Getting item with ID: ${id}`);
23
+
24
+ // Example response structure
25
+ return {
26
+ id,
27
+ data: 'sample data',
28
+ timestamp: new Date().toISOString()
29
+ };
30
+ } catch (error) {
31
+ console.error('Error getting item:', error);
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Create a new item
38
+ */
39
+ async createItem(data) {
40
+ try {
41
+ // TODO: Implement DynamoDB putItem logic
42
+ console.log('Creating new item:', data);
43
+
44
+ const newItem = {
45
+ id: data.id || `item-${Date.now()}`,
46
+ ...data,
47
+ createdAt: new Date().toISOString(),
48
+ updatedAt: new Date().toISOString()
49
+ };
50
+
51
+ return newItem;
52
+ } catch (error) {
53
+ console.error('Error creating item:', error);
54
+ throw error;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Update an existing item
60
+ */
61
+ async updateItem(id, data) {
62
+ try {
63
+ // TODO: Implement DynamoDB updateItem logic
64
+ console.log(`Updating item ${id}:`, data);
65
+
66
+ const updatedItem = {
67
+ id,
68
+ ...data,
69
+ updatedAt: new Date().toISOString()
70
+ };
71
+
72
+ return updatedItem;
73
+ } catch (error) {
74
+ console.error('Error updating item:', error);
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Delete an item by ID
81
+ */
82
+ async deleteItem(id) {
83
+ try {
84
+ // TODO: Implement DynamoDB deleteItem logic
85
+ console.log(`Deleting item with ID: ${id}`);
86
+
87
+ return true;
88
+ } catch (error) {
89
+ console.error('Error deleting item:', error);
90
+ throw error;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * List items with optional filtering
96
+ */
97
+ async listItems(filters) {
98
+ try {
99
+ // TODO: Implement DynamoDB scan/query logic
100
+ console.log('Listing items with filters:', filters);
101
+
102
+ // Example response
103
+ return [
104
+ {
105
+ id: 'item-1',
106
+ data: 'sample data 1',
107
+ timestamp: new Date().toISOString()
108
+ },
109
+ {
110
+ id: 'item-2',
111
+ data: 'sample data 2',
112
+ timestamp: new Date().toISOString()
113
+ }
114
+ ];
115
+ } catch (error) {
116
+ console.error('Error listing items:', error);
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Lambda handler for HTTP requests
123
+ */
124
+ async handleRequest(event, context) {
125
+ try {
126
+ const {httpMethod, pathParameters, body, queryStringParameters} = event;
127
+ const id = pathParameters?.id;
128
+
129
+ let result;
130
+
131
+ switch (httpMethod) {
132
+ case 'GET':
133
+ if (id) {
134
+ result = await this.getItem(id);
135
+ } else {
136
+ result = await this.listItems(queryStringParameters);
137
+ }
138
+ break;
139
+
140
+ case 'POST':
141
+ const createData = body ? JSON.parse(body) : {};
142
+ result = await this.createItem(createData);
143
+ break;
144
+
145
+ case 'PUT':
146
+ case 'PATCH':
147
+ if (!id) {
148
+ return {
149
+ statusCode: 400,
150
+ headers: {
151
+ 'Content-Type': 'application/json',
152
+ 'Access-Control-Allow-Origin': '*'
153
+ },
154
+ body: JSON.stringify({error: 'ID is required for update operations'})
155
+ };
156
+ }
157
+ const updateData = body ? JSON.parse(body) : {};
158
+ result = await this.updateItem(id, updateData);
159
+ break;
160
+
161
+ case 'DELETE':
162
+ if (!id) {
163
+ return {
164
+ statusCode: 400,
165
+ headers: {
166
+ 'Content-Type': 'application/json',
167
+ 'Access-Control-Allow-Origin': '*'
168
+ },
169
+ body: JSON.stringify({error: 'ID is required for delete operations'})
170
+ };
171
+ }
172
+ await this.deleteItem(id);
173
+ result = {message: 'Item deleted successfully'};
174
+ break;
175
+
176
+ default:
177
+ return {
178
+ statusCode: 405,
179
+ headers: {
180
+ 'Content-Type': 'application/json',
181
+ 'Access-Control-Allow-Origin': '*'
182
+ },
183
+ body: JSON.stringify({error: 'Method not allowed'})
184
+ };
185
+ }
186
+
187
+ return {
188
+ statusCode: 200,
189
+ headers: {
190
+ 'Content-Type': 'application/json',
191
+ 'Access-Control-Allow-Origin': '*'
192
+ },
193
+ body: JSON.stringify(result)
194
+ };
195
+
196
+ } catch (error) {
197
+ console.error('Handler error:', error);
198
+
199
+ return {
200
+ statusCode: 500,
201
+ headers: {
202
+ 'Content-Type': 'application/json',
203
+ 'Access-Control-Allow-Origin': '*'
204
+ },
205
+ body: JSON.stringify({
206
+ error: 'Internal server error',
207
+ message: error instanceof Error ? error.message : 'Unknown error'
208
+ })
209
+ };
210
+ }
211
+ }
212
+ }
213
+
214
+ // Export the handler function for Lambda
215
+ export const handler = async (event, context) => {
216
+ const dataLayer = new DataLayer();
217
+ return dataLayer.handleRequest(event, context);
218
+ };
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
3
+ * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
4
+ */
5
+
6
+ import {DataLayer, handler} from './DataLayer.js';
7
+
8
+ describe('DataLayer', () => {
9
+ let dataLayer;
10
+ let mockContext;
11
+
12
+ beforeEach(() => {
13
+ dataLayer = new DataLayer({
14
+ tableName: 'test-table',
15
+ region: 'us-east-1'
16
+ });
17
+
18
+ mockContext = {
19
+ awsRequestId: 'test-request-id',
20
+ functionName: 'test-function',
21
+ functionVersion: '$LATEST',
22
+ getRemainingTimeInMillis: () => 30000,
23
+ invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:test-function',
24
+ logGroupName: '/aws/lambda/test-function',
25
+ logStreamName: 'test-log-stream',
26
+ memoryLimitInMB: '128'
27
+ };
28
+ });
29
+
30
+ describe('getItem', () => {
31
+ it('should get an item by ID', async () => {
32
+ const result = await dataLayer.getItem('test-id');
33
+
34
+ expect(result).toEqual({
35
+ id: 'test-id',
36
+ data: 'sample data',
37
+ timestamp: expect.any(String)
38
+ });
39
+ });
40
+ });
41
+
42
+ describe('createItem', () => {
43
+ it('should create a new item', async () => {
44
+ const itemData = {
45
+ name: 'Test Item',
46
+ description: 'A test item'
47
+ };
48
+
49
+ const result = await dataLayer.createItem(itemData);
50
+
51
+ expect(result).toEqual({
52
+ id: expect.stringMatching(/^item-\d+$/),
53
+ name: 'Test Item',
54
+ description: 'A test item',
55
+ createdAt: expect.any(String),
56
+ updatedAt: expect.any(String)
57
+ });
58
+ });
59
+
60
+ it('should create an item with custom ID', async () => {
61
+ const itemData = {
62
+ id: 'custom-id',
63
+ name: 'Test Item'
64
+ };
65
+
66
+ const result = await dataLayer.createItem(itemData);
67
+
68
+ expect(result.id).toBe('custom-id');
69
+ expect(result.name).toBe('Test Item');
70
+ });
71
+ });
72
+
73
+ describe('updateItem', () => {
74
+ it('should update an existing item', async () => {
75
+ const updateData = {
76
+ name: 'Updated Item',
77
+ description: 'Updated description'
78
+ };
79
+
80
+ const result = await dataLayer.updateItem('test-id', updateData);
81
+
82
+ expect(result).toEqual({
83
+ id: 'test-id',
84
+ name: 'Updated Item',
85
+ description: 'Updated description',
86
+ updatedAt: expect.any(String)
87
+ });
88
+ });
89
+ });
90
+
91
+ describe('deleteItem', () => {
92
+ it('should delete an item by ID', async () => {
93
+ const result = await dataLayer.deleteItem('test-id');
94
+
95
+ expect(result).toBe(true);
96
+ });
97
+ });
98
+
99
+ describe('listItems', () => {
100
+ it('should list items without filters', async () => {
101
+ const result = await dataLayer.listItems();
102
+
103
+ expect(Array.isArray(result)).toBe(true);
104
+ expect(result.length).toBeGreaterThan(0);
105
+ expect(result[0]).toHaveProperty('id');
106
+ expect(result[0]).toHaveProperty('data');
107
+ expect(result[0]).toHaveProperty('timestamp');
108
+ });
109
+
110
+ it('should list items with filters', async () => {
111
+ const filters = {
112
+ status: 'active'
113
+ };
114
+
115
+ const result = await dataLayer.listItems(filters);
116
+
117
+ expect(Array.isArray(result)).toBe(true);
118
+ });
119
+ });
120
+
121
+ describe('handleRequest', () => {
122
+ it('should handle GET request for single item', async () => {
123
+ const event = {
124
+ httpMethod: 'GET',
125
+ pathParameters: {id: 'test-id'},
126
+ body: null,
127
+ queryStringParameters: null
128
+ };
129
+
130
+ const result = await dataLayer.handleRequest(event, mockContext);
131
+
132
+ expect(result.statusCode).toBe(200);
133
+ expect(result.headers['Content-Type']).toBe('application/json');
134
+ expect(result.headers['Access-Control-Allow-Origin']).toBe('*');
135
+
136
+ const body = JSON.parse(result.body);
137
+ expect(body.id).toBe('test-id');
138
+ });
139
+
140
+ it('should handle GET request for list items', async () => {
141
+ const event = {
142
+ httpMethod: 'GET',
143
+ pathParameters: null,
144
+ body: null,
145
+ queryStringParameters: {status: 'active'}
146
+ };
147
+
148
+ const result = await dataLayer.handleRequest(event, mockContext);
149
+
150
+ expect(result.statusCode).toBe(200);
151
+ const body = JSON.parse(result.body);
152
+ expect(Array.isArray(body)).toBe(true);
153
+ });
154
+
155
+ it('should handle POST request', async () => {
156
+ const event = {
157
+ httpMethod: 'POST',
158
+ pathParameters: null,
159
+ body: JSON.stringify({
160
+ name: 'New Item',
161
+ description: 'A new item'
162
+ }),
163
+ queryStringParameters: null
164
+ };
165
+
166
+ const result = await dataLayer.handleRequest(event, mockContext);
167
+
168
+ expect(result.statusCode).toBe(200);
169
+ const body = JSON.parse(result.body);
170
+ expect(body.name).toBe('New Item');
171
+ expect(body.description).toBe('A new item');
172
+ });
173
+
174
+ it('should handle PUT request', async () => {
175
+ const event = {
176
+ httpMethod: 'PUT',
177
+ pathParameters: {id: 'test-id'},
178
+ body: JSON.stringify({
179
+ name: 'Updated Item'
180
+ }),
181
+ queryStringParameters: null
182
+ };
183
+
184
+ const result = await dataLayer.handleRequest(event, mockContext);
185
+
186
+ expect(result.statusCode).toBe(200);
187
+ const body = JSON.parse(result.body);
188
+ expect(body.id).toBe('test-id');
189
+ expect(body.name).toBe('Updated Item');
190
+ });
191
+
192
+ it('should handle DELETE request', async () => {
193
+ const event = {
194
+ httpMethod: 'DELETE',
195
+ pathParameters: {id: 'test-id'},
196
+ body: null,
197
+ queryStringParameters: null
198
+ };
199
+
200
+ const result = await dataLayer.handleRequest(event, mockContext);
201
+
202
+ expect(result.statusCode).toBe(200);
203
+ const body = JSON.parse(result.body);
204
+ expect(body.message).toBe('Item deleted successfully');
205
+ });
206
+
207
+ it('should return 400 for PUT without ID', async () => {
208
+ const event = {
209
+ httpMethod: 'PUT',
210
+ pathParameters: null,
211
+ body: JSON.stringify({name: 'Updated Item'}),
212
+ queryStringParameters: null
213
+ };
214
+
215
+ const result = await dataLayer.handleRequest(event, mockContext);
216
+
217
+ expect(result.statusCode).toBe(400);
218
+ const body = JSON.parse(result.body);
219
+ expect(body.error).toBe('ID is required for update operations');
220
+ });
221
+
222
+ it('should return 400 for DELETE without ID', async () => {
223
+ const event = {
224
+ httpMethod: 'DELETE',
225
+ pathParameters: null,
226
+ body: null,
227
+ queryStringParameters: null
228
+ };
229
+
230
+ const result = await dataLayer.handleRequest(event, mockContext);
231
+
232
+ expect(result.statusCode).toBe(400);
233
+ const body = JSON.parse(result.body);
234
+ expect(body.error).toBe('ID is required for delete operations');
235
+ });
236
+
237
+ it('should return 405 for unsupported method', async () => {
238
+ const event = {
239
+ httpMethod: 'OPTIONS',
240
+ pathParameters: null,
241
+ body: null,
242
+ queryStringParameters: null
243
+ };
244
+
245
+ const result = await dataLayer.handleRequest(event, mockContext);
246
+
247
+ expect(result.statusCode).toBe(405);
248
+ const body = JSON.parse(result.body);
249
+ expect(body.error).toBe('Method not allowed');
250
+ });
251
+ });
252
+
253
+ describe('handler function', () => {
254
+ it('should work as Lambda handler', async () => {
255
+ const event = {
256
+ httpMethod: 'GET',
257
+ pathParameters: {id: 'test-id'},
258
+ body: null,
259
+ queryStringParameters: null
260
+ };
261
+
262
+ const result = await handler(event, mockContext);
263
+
264
+ expect(result.statusCode).toBe(200);
265
+ expect(result.headers['Content-Type']).toBe('application/json');
266
+ });
267
+ });
268
+ });