@lafken/common 0.7.0 → 0.8.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 CHANGED
@@ -1,66 +1,414 @@
1
1
  # @lafken/common
2
2
 
3
- `@lafken/common` is the core utility package for the Lafken framework. It provides the essential factory functions and utilities used to create the decorators that define infrastructure resources and Lambda handlers throughout the ecosystem.
3
+ `@lafken/common` is the core utility package for the Lafken framework. It provides the decorator factory functions, metadata reflection utilities, and shared types that power every `@lafken/*` package. If a Lafken package defines a decorator or reads infrastructure metadata, it depends on `@lafken/common`.
4
4
 
5
- ## Features
5
+ ## Installation
6
6
 
7
- ### Decorator Factories
7
+ ```bash
8
+ pnpm add @lafken/common
9
+ ```
10
+
11
+ ## Overview
8
12
 
9
- The package exports powerful factories to create custom decorators that integrate with the framework's metadata system.
13
+ Lafken uses TypeScript decorators to declare infrastructure. This package provides the factories that create those decorators and the utilities that read the metadata they produce:
10
14
 
11
- #### `createResourceDecorator`
15
+ | Factory | Level | Purpose |
16
+ | -------------------------- | ------ | -------------------------------------------- |
17
+ | `createResourceDecorator` | Class | Mark a class as a deployable resource |
18
+ | `createLambdaDecorator` | Method | Mark a method as a Lambda handler |
19
+ | `createEventDecorator` | Param | Bind a method parameter to the Lambda event |
20
+ | `createFieldDecorator` | Prop | Describe a typed field inside a payload class |
21
+ | `createPayloadDecorator` | Class | Define a named payload schema |
12
22
 
13
- Use this factory to create class-level decorators that mark a class as a deployable resource (e.g., a State Machine, a Queue, or a custom Event).
23
+ ## Decorator Factories
14
24
 
15
- It automatically captures:
16
- - The resource name.
17
- - The file path and folder name (for bundling).
18
- - Custom metadata defined in your props.
25
+ ### `createResourceDecorator`
26
+
27
+ Creates a **class-level** decorator that marks a class as an infrastructure resource. The factory automatically captures the resource name, the file path and folder (used for Lambda bundling), and any custom metadata you define.
19
28
 
20
29
  ```typescript
21
30
  import { createResourceDecorator } from '@lafken/common';
22
31
 
23
- export const MyCustomResource = createResourceDecorator({
24
- type: 'MY_CUSTOM_RESOURCE',
25
- callerFileIndex: 5, // Adjusts stack trace to find the caller file
32
+ export const RESOURCE_TYPE = 'MY_SERVICE' as const;
33
+
34
+ export interface MyServiceProps {
35
+ name?: string;
36
+ retryCount?: number;
37
+ }
38
+
39
+ export const MyService = createResourceDecorator<MyServiceProps>({
40
+ type: RESOURCE_TYPE,
41
+ callerFileIndex: 5, // Stack-trace index to resolve caller file
42
+ getMetadata: (props) => ({ // Optional — transform props before storing
43
+ ...props,
44
+ retryCount: props.retryCount ?? 3,
45
+ }),
26
46
  });
47
+ ```
48
+
49
+ Usage:
27
50
 
28
- // Usage
29
- @MyCustomResource({ ... })
30
- export class MyService { ... }
51
+ ```typescript
52
+ @MyService({ name: 'notifications', retryCount: 5 })
53
+ export class NotificationService { ... }
31
54
  ```
32
55
 
33
- #### `createLambdaDecorator`
56
+ **Captured metadata** (`ResourceMetadata`):
57
+
58
+ | Field | Description |
59
+ | -------------- | ---------------------------------------- |
60
+ | `type` | Resolver identifier (`MY_SERVICE`) |
61
+ | `name` | Explicit name or the class name |
62
+ | `foldername` | Directory of the decorated file |
63
+ | `filename` | File name (without `.js` extension) |
64
+ | `originalName` | Original class name (for asset naming) |
65
+ | `minify` | Whether to minify the bundle (`true`) |
66
+
67
+ ### `createLambdaDecorator`
34
68
 
35
- Use this factory to create method-level decorators that mark methods as Lambda function handlers. It handles:
36
- - Method metadata reflection.
37
- - Argument injection (Event, Context, Callback).
69
+ Creates a **method-level** decorator that registers a method as a Lambda handler. It stores handler metadata and rewrites the method descriptor so the framework can inject arguments (`@Event`, `@Context`) at runtime.
38
70
 
39
71
  ```typescript
40
72
  import { createLambdaDecorator } from '@lafken/common';
73
+ import type { LambdaMetadata } from '@lafken/common';
74
+
75
+ export interface PublishProps {
76
+ name: string;
77
+ lambda?: LambdaProps;
78
+ }
41
79
 
42
- export const MyLambdaTrigger = <T>(props: T) =>
43
- createLambdaDecorator({
80
+ export interface PublishMetadata extends PublishProps {
81
+ name: string;
82
+ }
83
+
84
+ export const Publish = (props: PublishProps) =>
85
+ createLambdaDecorator<PublishProps, PublishMetadata>({
44
86
  getLambdaMetadata: (props, methodName) => ({
45
87
  ...props,
46
88
  name: methodName,
47
89
  }),
48
90
  })(props);
91
+ ```
92
+
93
+ Usage:
94
+
95
+ ```typescript
96
+ class NotificationService {
97
+ @Publish({ name: 'send-email' })
98
+ sendEmail(@Event() event: EmailPayload) {
99
+ // handler logic
100
+ }
101
+ }
102
+ ```
103
+
104
+ **`LambdaProps`** — Optional Lambda-level configuration available through the `lambda` property:
105
+
106
+ | Property | Type | Description |
107
+ | ------------- | ------------------- | --------------------------------------------- |
108
+ | `timeout` | `number` | Execution timeout in seconds |
109
+ | `memory` | `number` | Memory allocation in MB |
110
+ | `runtime` | `24 \| 22 \| 20` | Node.js runtime version |
111
+ | `services` | `ServicesValues` | IAM service permissions |
112
+ | `env` | `EnvironmentValue` | Environment variables (static or dynamic) |
113
+ | `tags` | `Record<string, string>` | Resource tags |
114
+ | `enableTrace` | `boolean` | Enable AWS X-Ray tracing |
115
+
116
+ ### `createEventDecorator`
117
+
118
+ Creates a **parameter-level** decorator that binds a method parameter to the incoming Lambda event. It works with `createFieldDecorator` to map typed payload classes onto the raw event.
119
+
120
+ ```typescript
121
+ import { createEventDecorator } from '@lafken/common';
122
+
123
+ export const Event = createEventDecorator({
124
+ prefix: 'my-service',
125
+ enableInLambdaInvocation: false, // Only capture metadata during build
126
+ });
127
+ ```
128
+
129
+ Usage:
130
+
131
+ ```typescript
132
+ class NotificationService {
133
+ @Publish({ name: 'send-email' })
134
+ sendEmail(@Event(EmailPayload) event: EmailPayload) { ... }
135
+ }
136
+ ```
137
+
138
+ ### `Context`
139
+
140
+ A built-in parameter decorator that injects the Lambda execution context:
141
+
142
+ ```typescript
143
+ import { Context } from '@lafken/common';
49
144
 
50
- // Usage
51
145
  class MyService {
52
- @MyLambdaTrigger({ ... })
53
- handleRequest(@Event() event: any) { ... }
146
+ @Handler()
147
+ process(@Event(Input) event: Input, @Context() ctx: any) {
148
+ console.log(ctx.functionName);
149
+ }
150
+ }
151
+ ```
152
+
153
+ ### `createFieldDecorator`
154
+
155
+ Creates a **property-level** decorator that describes a typed field inside a payload class. The field metadata is collected by resolvers to build event schemas (e.g., Step Functions input/output, API request bodies).
156
+
157
+ Supported types: `String`, `Number`, `Boolean`, nested classes, and arrays.
158
+
159
+ ```typescript
160
+ import { createFieldDecorator } from '@lafken/common';
161
+
162
+ export const Field = createFieldDecorator({
163
+ prefix: 'my-service',
164
+ getMetadata: () => ({}),
165
+ });
166
+ ```
167
+
168
+ Usage:
169
+
170
+ ```typescript
171
+ class Address {
172
+ @Field()
173
+ street: string;
174
+
175
+ @Field()
176
+ city: string;
177
+ }
178
+
179
+ class UserPayload {
180
+ @Field({ name: 'user_name' }) // Rename the field in the schema
181
+ name: string;
182
+
183
+ @Field()
184
+ age: number;
185
+
186
+ @Field({ type: Address }) // Nested object
187
+ address: Address;
188
+
189
+ @Field({ type: [String] }) // Array of primitives
190
+ tags: string[];
191
+ }
192
+ ```
193
+
194
+ ### `createPayloadDecorator`
195
+
196
+ Creates a **class-level** decorator that gives a payload class a name and optional metadata. This identity is used when resolvers reference the payload in generated infrastructure.
197
+
198
+ ```typescript
199
+ import { createPayloadDecorator } from '@lafken/common';
200
+
201
+ export const Payload = createPayloadDecorator({
202
+ prefix: 'my-service',
203
+ createUniqueId: true, // Append a counter if names collide
204
+ });
205
+ ```
206
+
207
+ Usage:
208
+
209
+ ```typescript
210
+ @Payload({ name: 'CreateUserInput' })
211
+ class CreateUserInput {
212
+ @Field()
213
+ email: string;
214
+ }
215
+ ```
216
+
217
+ ## Metadata Utilities
218
+
219
+ Resolvers use these functions to read the metadata produced by the decorators above.
220
+
221
+ ### `getResourceMetadata`
222
+
223
+ Returns the `ResourceMetadata` stored on a class by `createResourceDecorator`:
224
+
225
+ ```typescript
226
+ import { getResourceMetadata } from '@lafken/common';
227
+
228
+ const metadata = getResourceMetadata(NotificationService);
229
+ // { type: 'MY_SERVICE', name: 'notifications', foldername: '...', ... }
230
+ ```
231
+
232
+ ### `getResourceHandlerMetadata`
233
+
234
+ Returns an array of handler metadata stored by `createLambdaDecorator`:
235
+
236
+ ```typescript
237
+ import { getResourceHandlerMetadata } from '@lafken/common';
238
+
239
+ const handlers = getResourceHandlerMetadata<PublishMetadata>(NotificationService);
240
+ // [{ name: 'sendEmail', ... }]
241
+ ```
242
+
243
+ ### `getMetadataByKey` / `getMetadataPrototypeByKey`
244
+
245
+ Low-level helpers to read any Reflect metadata by key from a class or its prototype:
246
+
247
+ ```typescript
248
+ import { getMetadataByKey, getMetadataPrototypeByKey } from '@lafken/common';
249
+
250
+ const payload = getMetadataByKey<PayloadMetadata>(MyClass, 'my-service:lafken:payload');
251
+ const fields = getMetadataPrototypeByKey<FieldMetadata[]>(MyClass, 'my-service:lafken:field');
252
+ ```
253
+
254
+ ## Build Environment
255
+
256
+ Decorators only capture metadata when the build environment flag is set. This prevents metadata side-effects during normal runtime execution.
257
+
258
+ - **`isBuildEnvironment()`** — Returns `true` when the `LAFKEN_CONTEXT` environment variable equals `BUILD`.
259
+ - **`enableBuildEnvVariable()`** — Sets the flag. **Required in tests** before declaring any decorated class.
260
+
261
+ ```typescript
262
+ import { enableBuildEnvVariable } from '@lafken/common';
263
+
264
+ describe('My resolver', () => {
265
+ enableBuildEnvVariable();
266
+
267
+ @MyService({ name: 'test' })
268
+ class TestResource { ... }
269
+
270
+ it('should capture metadata', () => {
271
+ const meta = getResourceMetadata(TestResource);
272
+ expect(meta.name).toBe('test');
273
+ });
274
+ });
275
+ ```
276
+
277
+ ## String Utilities
278
+
279
+ General-purpose string helpers used throughout the framework:
280
+
281
+ | Function | Description | Example |
282
+ | ---------------------- | ---------------------------------------------------- | -------------------------------- |
283
+ | `capitalize(str)` | Uppercase first letter | `'hello'` → `'Hello'` |
284
+ | `kebabCase(str)` | Convert to kebab-case | `'MyService'` → `'my-service'` |
285
+ | `cleanString(str)` | Remove non-alphanumeric characters | `'a-b_c'` → `'abc'` |
286
+ | `cleanAndCapitalize(str)` | Clean + capitalize each word | `'my-service'` → `'MyService'` |
287
+ | `cleanTemplateString(str)` | Trim + collapse multiline strings into one line | — |
288
+
289
+ ## Shared Types
290
+
291
+ ### Services & Permissions
292
+
293
+ The `Services` type provides typed IAM permission declarations for Lambda handlers:
294
+
295
+ ```typescript
296
+ import type { Services } from '@lafken/common';
297
+
298
+ // Shorthand — grants full service access
299
+ const services: Services[] = ['dynamodb', 's3'];
300
+
301
+ // Fine-grained — specific actions and resources
302
+ const services: Services[] = [
303
+ { type: 'dynamodb', permissions: ['GetItem', 'PutItem'] },
304
+ { type: 's3', permissions: ['GetObject'], resources: ['arn:aws:s3:::my-bucket/*'] },
305
+ { type: 'custom', serviceName: 'ses', permissions: ['SendEmail'] },
306
+ ];
307
+ ```
308
+
309
+ Supported service types: `dynamodb`, `s3`, `lambda`, `cloudwatch`, `sqs`, `state_machine`, `kms`, `ssm`, `event`, and `custom`.
310
+
311
+ ### Environment Variables
312
+
313
+ ```typescript
314
+ import type { EnvironmentValue } from '@lafken/common';
315
+
316
+ // Static values
317
+ const env: EnvironmentValue = { TABLE_NAME: 'users' };
318
+
319
+ // Dynamic values — resolved at deploy time via resource references
320
+ const env: EnvironmentValue = ({ getResourceValue }) => ({
321
+ TABLE_ARN: getResourceValue('dynamo::users-table', 'arn'),
322
+ });
323
+ ```
324
+
325
+ ### Duration
326
+
327
+ ```typescript
328
+ import type { Duration } from '@lafken/common';
329
+
330
+ const timeout: Duration = 30; // seconds
331
+ const ttl: Duration = { type: 'days', duration: 7 }; // 7 days
332
+ ```
333
+
334
+ ### Type-Safe Resource References
335
+
336
+ The package provides augmentable interfaces that enable type-safe resource names across modules. Packages extend these interfaces so that `getResourceValue` calls are validated at compile time:
337
+
338
+ ```typescript
339
+ // In your lafken-types.d.ts
340
+ declare module '@lafken/common' {
341
+ interface ModulesAvailable {
342
+ core: {
343
+ Queue: { 'email-queue': string };
344
+ };
345
+ }
346
+ interface DynamoTableAvailable {
347
+ 'users-table': string;
348
+ }
54
349
  }
55
350
  ```
56
351
 
57
- ### Metadata Utilities
352
+ ## API Reference
353
+
354
+ ### Decorator Factories
355
+
356
+ | Export | Description |
357
+ | -------------------------- | ------------------------------------------ |
358
+ | `createResourceDecorator` | Factory for class-level resource decorators |
359
+ | `createLambdaDecorator` | Factory for method-level handler decorators |
360
+ | `createEventDecorator` | Factory for parameter-level event binding |
361
+ | `createFieldDecorator` | Factory for property-level field metadata |
362
+ | `createPayloadDecorator` | Factory for class-level payload naming |
363
+ | `Context` | Parameter decorator for Lambda context |
364
+
365
+ ### Metadata Readers
366
+
367
+ | Export | Description |
368
+ | ---------------------------- | ------------------------------------------ |
369
+ | `getResourceMetadata` | Read class resource metadata |
370
+ | `getResourceHandlerMetadata` | Read method handler metadata |
371
+ | `getMetadataByKey` | Read metadata by key from a class |
372
+ | `getMetadataPrototypeByKey` | Read metadata by key from a prototype |
373
+
374
+ ### Utilities
375
+
376
+ | Export | Description |
377
+ | ------------------------- | ---------------------------------------- |
378
+ | `enableBuildEnvVariable` | Enable build mode for decorator capture |
379
+ | `isBuildEnvironment` | Check if build mode is active |
380
+ | `getCallerFileName` | Resolve the caller file from the stack |
381
+ | `capitalize` | Capitalize a string |
382
+ | `kebabCase` | Convert to kebab-case |
383
+ | `cleanString` | Strip non-alphanumeric characters |
384
+ | `cleanAndCapitalize` | Clean and capitalize each word |
385
+ | `cleanTemplateString` | Collapse multiline string to one line |
386
+
387
+ ### Constants
388
+
389
+ | Export | Description |
390
+ | ---------------------- | ------------------------------------ |
391
+ | `LAFKEN_CONTEXT` | Environment variable name |
392
+ | `LAFKEN_CONTEXT_VALUE` | Expected value for build mode |
58
393
 
59
- `@lafken/common` provides utilities to read the metadata stored by these decorators, which resolvers use to build the actual infrastructure.
394
+ ### Key Types
60
395
 
61
- - `getResourceMetadata(target)`: Retrieves metadata from a resource class.
62
- - `getResourceHandlerMetadata(target)`: Retrieves metadata for all lambda handlers in a class.
396
+ | Export | Description |
397
+ | -------------------- | --------------------------------------------------- |
398
+ | `ResourceProps` | Base props for resource decorators |
399
+ | `ResourceMetadata` | Metadata shape stored by resource decorators |
400
+ | `LambdaProps` | Lambda configuration (timeout, memory, runtime, ...) |
401
+ | `LambdaMetadata` | Metadata shape for handler methods |
402
+ | `FieldMetadata` | Discriminated union of field types |
403
+ | `PayloadMetadata` | Metadata shape for payload classes |
404
+ | `Services` | IAM permission declaration type |
405
+ | `ServicesValues` | Array or function returning `Services[]` |
406
+ | `EnvironmentValue` | Static or dynamic environment variables |
407
+ | `Duration` | Seconds or `{ type, duration }` object |
408
+ | `ClassResource` | Generic class constructor type |
409
+ | `GetResourceValue` | Callback type for cross-resource references |
410
+ | `DeepPartial<T>` | Recursive partial type utility |
63
411
 
64
- ## Usage
412
+ ## License
65
413
 
66
- This package is intended for internal use within the Lafken framework or for advanced users extending the framework with custom resource types. It ensures consistent metadata handling across all `@lafken/*` packages.
414
+ MIT
@@ -61,10 +61,13 @@ const getFieldMetadata = (props) => {
61
61
  destinationName,
62
62
  name: fieldProps?.name || destinationName,
63
63
  };
64
- const primitiveType = (0, exports.getPrimitiveType)(type);
64
+ let primitiveType = (0, exports.getPrimitiveType)(type);
65
+ if (!primitiveType && fieldProps?.type) {
66
+ primitiveType = (0, exports.getPrimitiveType)(fieldProps.type);
67
+ }
65
68
  const typeHasValue = exports.mapTypeofValueToPrimitiveType[typeof fieldProps?.type];
66
69
  if (fieldProps?.type !== undefined) {
67
- if (typeof fieldProps.type === 'function') {
70
+ if (typeof fieldProps.type === 'function' && !primitiveType) {
68
71
  return getObjectMetadata(metadata, fieldProps.type, prefix);
69
72
  }
70
73
  if (Array.isArray(fieldProps.type)) {
@@ -4,5 +4,4 @@ import { type CreateEventDecoratorProps, type CreateLambdaDecoratorProps, Lambda
4
4
  export declare const reflectArgumentMethod: (target: Function, methodName: string, type: LambdaArgumentTypes) => void;
5
5
  export declare const createLambdaDecorator: <T, M>({ getLambdaMetadata, descriptorValue, argumentParser, }: CreateLambdaDecoratorProps<T, M>) => (props?: T) => (target: any, methodName: string, descriptor: PropertyDescriptor) => any;
6
6
  export declare const createEventDecorator: ({ enableInLambdaInvocation, prefix }: CreateEventDecoratorProps) => (eventField: AllowedTypes) => (target: any, methodName: string, _number: number) => void;
7
- export declare const Callback: () => (target: any, methodName: string, _number: number) => void;
8
7
  export declare const Context: () => (target: any, methodName: string, _number: number) => void;
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Context = exports.Callback = exports.createEventDecorator = exports.createLambdaDecorator = exports.reflectArgumentMethod = void 0;
3
+ exports.Context = exports.createEventDecorator = exports.createLambdaDecorator = exports.reflectArgumentMethod = void 0;
4
4
  require("reflect-metadata");
5
5
  const utils_1 = require("../../utils");
6
6
  const field_1 = require("../field");
7
7
  const lambda_types_1 = require("./lambda.types");
8
8
  const argumentsByType = {
9
9
  [lambda_types_1.LambdaArgumentTypes.event]: ({ event }) => event,
10
- [lambda_types_1.LambdaArgumentTypes.callback]: ({ callback }) => callback,
11
10
  [lambda_types_1.LambdaArgumentTypes.context]: ({ context }) => context,
12
11
  };
13
12
  const reflectArgumentMethod = (target, methodName, type) => {
@@ -30,8 +29,8 @@ const createLambdaDecorator = ({ getLambdaMetadata, descriptorValue, argumentPar
30
29
  ...argumentsByType,
31
30
  ...argumentParser,
32
31
  };
33
- descriptor.value = async (event, context, callback) => {
34
- const methodArguments = (lambdaArguments?.[methodName] || []).map((argumentType) => mapArgumentMethod[argumentType]({ event, context, methodName, target, callback }));
32
+ descriptor.value = async (event, context) => {
33
+ const methodArguments = (lambdaArguments?.[methodName] || []).map((argumentType) => mapArgumentMethod[argumentType]({ event, context, methodName, target }));
35
34
  const response = await originalValue.apply(this, methodArguments);
36
35
  return response;
37
36
  };
@@ -53,10 +52,6 @@ const createEventDecorator = ({ enableInLambdaInvocation = false, prefix }) => (
53
52
  reflectEventMetadata(target, methodName, lambda_types_1.LambdaReflectKeys.event_param, field);
54
53
  };
55
54
  exports.createEventDecorator = createEventDecorator;
56
- const Callback = () => (target, methodName, _number) => {
57
- (0, exports.reflectArgumentMethod)(target, methodName, lambda_types_1.LambdaArgumentTypes.callback);
58
- };
59
- exports.Callback = Callback;
60
55
  const Context = () => (target, methodName, _number) => {
61
56
  (0, exports.reflectArgumentMethod)(target, methodName, lambda_types_1.LambdaArgumentTypes.context);
62
57
  };
@@ -103,17 +103,15 @@ export declare enum LambdaReflectKeys {
103
103
  }
104
104
  export declare enum LambdaArgumentTypes {
105
105
  event = "event",
106
- callback = "callback",
107
106
  context = "context"
108
107
  }
109
108
  export type CallbackParam = (error: boolean | null, response?: any) => void;
110
109
  export type LambdaArguments = Record<string, LambdaArgumentTypes[]>;
111
- export type LambdaArgumentsType = Record<LambdaArgumentTypes, ({ event, context, callback, }: {
110
+ export type LambdaArgumentsType = Record<LambdaArgumentTypes, ({ event, context, }: {
112
111
  event: any;
113
112
  context: any;
114
113
  methodName: string;
115
114
  target: any;
116
- callback: CallbackParam;
117
115
  }) => any>;
118
116
  export interface CreateLambdaDecoratorProps<T, M> {
119
117
  getLambdaMetadata: (params: T, methodName: string) => M;
@@ -10,6 +10,5 @@ var LambdaReflectKeys;
10
10
  var LambdaArgumentTypes;
11
11
  (function (LambdaArgumentTypes) {
12
12
  LambdaArgumentTypes["event"] = "event";
13
- LambdaArgumentTypes["callback"] = "callback";
14
13
  LambdaArgumentTypes["context"] = "context";
15
14
  })(LambdaArgumentTypes || (exports.LambdaArgumentTypes = LambdaArgumentTypes = {}));
@@ -31,3 +31,7 @@ export type OnlyOneKey<T> = {
31
31
  export type StripReadonly<T> = {
32
32
  -readonly [P in keyof T]: StripReadonly<T[P]>;
33
33
  };
34
+ export type Primitive = string | number | boolean[];
35
+ export type OnlyTypeKeys<T, V> = {
36
+ [K in keyof T]: T[K] extends V ? K : never;
37
+ }[keyof T];
@@ -2,3 +2,4 @@ export declare const capitalize: (str: string) => string;
2
2
  export declare const kebabCase: (str: string) => string;
3
3
  export declare const cleanString: (str: string) => string;
4
4
  export declare const cleanTemplateString: (str: string) => string;
5
+ export declare const cleanAndCapitalize: (str: string) => string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cleanTemplateString = exports.cleanString = exports.kebabCase = exports.capitalize = void 0;
3
+ exports.cleanAndCapitalize = exports.cleanTemplateString = exports.cleanString = exports.kebabCase = exports.capitalize = void 0;
4
4
  const capitalize = (str) => {
5
5
  return str.charAt(0).toUpperCase() + str.slice(1);
6
6
  };
@@ -27,3 +27,10 @@ const cleanTemplateString = (str) => {
27
27
  .join(' ');
28
28
  };
29
29
  exports.cleanTemplateString = cleanTemplateString;
30
+ const cleanAndCapitalize = (str) => {
31
+ return str
32
+ .split(/[^a-zA-Z0-9]+/)
33
+ .map((word) => (0, exports.capitalize)(word))
34
+ .join('');
35
+ };
36
+ exports.cleanAndCapitalize = cleanAndCapitalize;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lafken/common",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "Lafken utilities - TypeScript decorator factories and metadata reflection for infrastructure-as-code decorators",
6
6
  "keywords": [
@@ -31,10 +31,12 @@
31
31
  "reflect-metadata": "0.2.2"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/jest": "30.0.0",
35
- "jest": "30.2.0",
36
- "ts-jest": "29.4.6",
37
- "ts-node": "10.9.2"
34
+ "@swc/core": "^1.15.11",
35
+ "@swc/helpers": "^0.5.18",
36
+ "@vitest/runner": "^4.0.18",
37
+ "cdktn-vitest": "^1.0.0",
38
+ "unplugin-swc": "^1.5.9",
39
+ "vitest": "^4.0.18"
38
40
  },
39
41
  "engines": {
40
42
  "node": ">=20.19"
@@ -44,9 +46,9 @@
44
46
  },
45
47
  "scripts": {
46
48
  "build": "pnpm clean && tsc -p ./tsconfig.build.json",
49
+ "check-types": "tsc --noEmit -p ./tsconfig.build.json",
47
50
  "clean": "rm -rf ./lib",
48
51
  "dev": "tsc -w",
49
- "test": "jest",
50
- "test:coverage": "jest --coverage"
52
+ "test": "vitest"
51
53
  }
52
54
  }