@kensio/yulin 1.21.27 → 1.21.28

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.
@@ -13,6 +13,10 @@ export default defineConfig({
13
13
  files: ["**/*.cff.js"],
14
14
  extends: [tseslint.configs.disableTypeChecked],
15
15
  languageOptions: {
16
+ // The typescript-eslint rules below read scope information only its own
17
+ // parser produces. Under ESLint's default parser, `no-unused-vars` takes
18
+ // every reference for a type-only one and reports each variable.
19
+ parser: tseslint.parser,
16
20
  parserOptions: {
17
21
  projectService: false,
18
22
  },
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether a declared Parameter `Type` holds a list.
3
+ *
4
+ * `CommaDelimitedList` and every `List<...>` type do, whatever the member
5
+ * type. A `Ref` to one resolves to a list of strings, `List<Number>` included.
6
+ */
7
+ export declare function isSimCfnParameterListType(type: string | undefined): boolean;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Whether a declared Parameter `Type` holds a list.
3
+ *
4
+ * `CommaDelimitedList` and every `List<...>` type do, whatever the member
5
+ * type. A `Ref` to one resolves to a list of strings, `List<Number>` included.
6
+ */
7
+ export function isSimCfnParameterListType(type) {
8
+ return type === "CommaDelimitedList" || (type?.startsWith("List<") ?? false);
9
+ }
@@ -13,6 +13,9 @@ interface SimCfnParameterValuesProperties {
13
13
  * the command wins over a template `Default`, and a Parameter declared as a
14
14
  * Parameter Store value type reads whichever of the two it ended up with as the
15
15
  * name to read.
16
+ *
17
+ * A `CommaDelimitedList` or `List<...>` Parameter is given its value as one
18
+ * comma-separated string, and holds it as the list of members.
16
19
  */
17
20
  export declare class SimCfnParameterValues {
18
21
  private readonly values;
@@ -29,5 +32,12 @@ export declare class SimCfnParameterValues {
29
32
  * `Default`.
30
33
  */
31
34
  private recordDefaults;
35
+ /**
36
+ * Split the value of each list-typed Parameter on its commas.
37
+ *
38
+ * Each member is trimmed of the spaces around it, as CloudFormation trims
39
+ * them. A value with no commas is a list of one.
40
+ */
41
+ private splitLists;
32
42
  }
33
43
  export {};
@@ -1,3 +1,4 @@
1
+ import { isSimCfnParameterListType } from "./sim-cfn-parameter-list-type.js";
1
2
  import { SimCfnParameterStoreValues } from "./store/sim-cfn-parameter-store-values.js";
2
3
  /**
3
4
  * The runtime value of every Parameter a Stack was created with.
@@ -6,6 +7,9 @@ import { SimCfnParameterStoreValues } from "./store/sim-cfn-parameter-store-valu
6
7
  * the command wins over a template `Default`, and a Parameter declared as a
7
8
  * Parameter Store value type reads whichever of the two it ended up with as the
8
9
  * name to read.
10
+ *
11
+ * A `CommaDelimitedList` or `List<...>` Parameter is given its value as one
12
+ * comma-separated string, and holds it as the list of members.
9
13
  */
10
14
  export class SimCfnParameterValues {
11
15
  values;
@@ -15,6 +19,7 @@ export class SimCfnParameterValues {
15
19
  this.storeValues = new SimCfnParameterStoreValues({ store });
16
20
  this.values = new Map(Object.entries(supplied));
17
21
  this.recordDefaults(definitions);
22
+ this.splitLists(definitions);
18
23
  this.storeValues.applyTo(this.values, definitions);
19
24
  }
20
25
  /** Every Parameter that resolved to a stand-in value. */
@@ -39,4 +44,19 @@ export class SimCfnParameterValues {
39
44
  }
40
45
  }
41
46
  }
47
+ /**
48
+ * Split the value of each list-typed Parameter on its commas.
49
+ *
50
+ * Each member is trimmed of the spaces around it, as CloudFormation trims
51
+ * them. A value with no commas is a list of one.
52
+ */
53
+ splitLists(definitions) {
54
+ for (const [parameterName, definition] of definitions) {
55
+ const value = this.values.get(parameterName);
56
+ if (typeof value === "string" &&
57
+ isSimCfnParameterListType(definition.Type)) {
58
+ this.values.set(parameterName, value.split(",").map((member) => member.trim()));
59
+ }
60
+ }
61
+ }
42
62
  }
@@ -5,9 +5,10 @@ import type { SimCfnParameterStoreReader } from "./store/sim-cfn-parameter-store
5
5
  * defaults and Parameter Store reads have been applied.
6
6
  *
7
7
  * A Parameter is given its value as a string, because AWS CloudFormation
8
- * command inputs provide ParameterValue as one. A Parameter declared as
9
- * `AWS::SSM::Parameter::Value<List<String>>` is given a parameter name and
10
- * resolves to the stored value split into a list, so a resolved value can be
8
+ * command inputs provide ParameterValue as one. A `CommaDelimitedList` or
9
+ * `List<...>` Parameter resolves to that string split into a list. So does an
10
+ * `AWS::SSM::Parameter::Value<List<String>>` Parameter, which is given a
11
+ * parameter name and splits the value stored under it. A resolved value can be
11
12
  * either.
12
13
  */
13
14
  export type SimCloudFormationParameterValue = string | string[];
@@ -61,8 +62,9 @@ export type SimCfnParametersContext = Pick<SimCfnParametersProperties, "definiti
61
62
  *
62
63
  * Most fields are recorded for structural typing/documentation. Runtime
63
64
  * behavior applies string Default values when a command does not provide an
64
- * explicit Parameter value, and reads an `AWS::SSM::Parameter::Value<...>`
65
- * Type from simulated Parameter Store.
65
+ * explicit Parameter value, splits the value of a `CommaDelimitedList` or
66
+ * `List<...>` Type, and reads an `AWS::SSM::Parameter::Value<...>` Type from
67
+ * simulated Parameter Store.
66
68
  */
67
69
  export interface SimCfnParameterDefinition {
68
70
  readonly Type?: string | undefined;
@@ -1,3 +1,4 @@
1
+ import { isSimCfnParameterListType } from "../sim-cfn-parameter-list-type.js";
1
2
  /** The Parameter type that holds a Parameter Store name. */
2
3
  const parameterStoreValuePrefix = "AWS::SSM::Parameter::Value<";
3
4
  /**
@@ -14,6 +15,6 @@ export function simCfnParameterStoreValueType(declaredType) {
14
15
  }
15
16
  const innerType = declaredType.slice(parameterStoreValuePrefix.length, -1);
16
17
  return {
17
- list: innerType === "CommaDelimitedList" || innerType.startsWith("List<"),
18
+ list: isSimCfnParameterListType(innerType),
18
19
  };
19
20
  }
@@ -9,19 +9,25 @@ import type { SimCfnResolveContext } from "../../../resolve/sim-cfn-resolve-cont
9
9
  * {
10
10
  * "Fn::Join": ["-", ["a", "b", { "Ref": "Name" }]]
11
11
  * }
12
+ *
13
+ * The values may also come from one function that returns the whole list:
14
+ *
15
+ * {
16
+ * "Fn::Join": [",", { "Fn::GetAtt": ["Zone", "NameServers"] }]
17
+ * }
12
18
  */
13
19
  export declare class SimCfnFnJoin extends SimCfnNode {
14
20
  private readonly delimiter;
15
21
  private readonly values;
16
- constructor(delimiter: string, values: readonly SimCfnNode[]);
22
+ constructor(delimiter: string, values: SimCfnNode);
17
23
  /**
18
- * Resolve each value and join them with the delimiter.
24
+ * Resolve the values and join them with the delimiter.
19
25
  *
20
- * Joining happens only when every value has resolved to a string. If any
21
- * value is still an unresolved expression (for example a Resource `Ref`
22
- * during the up-front pass before Resources exist), this node re-emits
23
- * itself in template form. A later resolution pass can finish it once the
24
- * referenced Resources are available.
26
+ * Joining happens only when the values have resolved to a list of strings.
27
+ * If the list, or any value in it, is still an unresolved expression (for
28
+ * example a Resource `Ref` during the up-front pass before Resources exist),
29
+ * this node re-emits itself in template form. A later resolution pass can
30
+ * finish it once the referenced Resources are available.
25
31
  *
26
32
  * A dynamic reference can be assembled out of the joined values, as CDK
27
33
  * writes one whenever the secret it reads sits in the same Stack: the
@@ -32,16 +38,15 @@ export declare class SimCfnFnJoin extends SimCfnNode {
32
38
  */
33
39
  resolve(context: SimCfnResolveContext): SimCfnTemplateValue;
34
40
  /**
35
- * Collect referenced names from every joined value.
41
+ * Collect referenced names from the values.
36
42
  */
37
43
  referencedNames(): string[];
38
- private resolveValue;
39
44
  /**
40
- * Whether a resolved value is still an unresolved intrinsic expression.
45
+ * Refuse a value that can never become a string.
41
46
  *
42
- * Only object-shaped values (a preserved `Ref` or nested function object)
43
- * are treated as deferred. Other non-string primitives such as numbers are
44
- * genuine type errors.
47
+ * A string joins now, and an unresolved expression may join on a later
48
+ * pass. Anything else (a number, a nested list, a plain object) is a type
49
+ * error, as CloudFormation joins a list of strings only.
45
50
  */
46
- private isDeferredExpression;
51
+ private assertJoinable;
47
52
  }
@@ -1,4 +1,5 @@
1
1
  import { SimCfnNode } from "../../sim-cfn-node.js";
2
+ import { isSimCfnUnresolvedExpression } from "../../../value/sim-cfn-unresolved-expression.js";
2
3
  /**
3
4
  * Simulated CloudFormation `Fn::Join` intrinsic function.
4
5
  *
@@ -7,6 +8,12 @@ import { SimCfnNode } from "../../sim-cfn-node.js";
7
8
  * {
8
9
  * "Fn::Join": ["-", ["a", "b", { "Ref": "Name" }]]
9
10
  * }
11
+ *
12
+ * The values may also come from one function that returns the whole list:
13
+ *
14
+ * {
15
+ * "Fn::Join": [",", { "Fn::GetAtt": ["Zone", "NameServers"] }]
16
+ * }
10
17
  */
11
18
  export class SimCfnFnJoin extends SimCfnNode {
12
19
  delimiter;
@@ -17,13 +24,13 @@ export class SimCfnFnJoin extends SimCfnNode {
17
24
  this.values = values;
18
25
  }
19
26
  /**
20
- * Resolve each value and join them with the delimiter.
27
+ * Resolve the values and join them with the delimiter.
21
28
  *
22
- * Joining happens only when every value has resolved to a string. If any
23
- * value is still an unresolved expression (for example a Resource `Ref`
24
- * during the up-front pass before Resources exist), this node re-emits
25
- * itself in template form. A later resolution pass can finish it once the
26
- * referenced Resources are available.
29
+ * Joining happens only when the values have resolved to a list of strings.
30
+ * If the list, or any value in it, is still an unresolved expression (for
31
+ * example a Resource `Ref` during the up-front pass before Resources exist),
32
+ * this node re-emits itself in template form. A later resolution pass can
33
+ * finish it once the referenced Resources are available.
27
34
  *
28
35
  * A dynamic reference can be assembled out of the joined values, as CDK
29
36
  * writes one whenever the secret it reads sits in the same Stack: the
@@ -33,37 +40,49 @@ export class SimCfnFnJoin extends SimCfnNode {
33
40
  * out of its variables.
34
41
  */
35
42
  resolve(context) {
36
- const resolved = this.values.map((value) => this.resolveValue(value, context));
37
- if (resolved.every((value) => typeof value === "string")) {
38
- const joined = resolved.join(this.delimiter);
43
+ const values = this.values.resolve(context);
44
+ if (isSimCfnUnresolvedExpression(values)) {
45
+ return { "Fn::Join": [this.delimiter, values] };
46
+ }
47
+ if (!Array.isArray(values)) {
48
+ throw new TypeError(`Sim CloudFormation Fn::Join values must resolve to a list, got ${describe(values)}`);
49
+ }
50
+ for (const value of values) {
51
+ this.assertJoinable(value);
52
+ }
53
+ if (values.every((value) => typeof value === "string")) {
54
+ const joined = values.join(this.delimiter);
39
55
  return context.dynamicReferences?.substitute(joined) ?? joined;
40
56
  }
41
- return { "Fn::Join": [this.delimiter, resolved] };
57
+ return { "Fn::Join": [this.delimiter, values] };
42
58
  }
43
59
  /**
44
- * Collect referenced names from every joined value.
60
+ * Collect referenced names from the values.
45
61
  */
46
62
  referencedNames() {
47
- return this.values.flatMap((value) => value.referencedNames());
48
- }
49
- resolveValue(value, context) {
50
- const resolved = value.resolve(context);
51
- if (typeof resolved === "string") {
52
- return resolved;
53
- }
54
- if (this.isDeferredExpression(resolved)) {
55
- return resolved;
56
- }
57
- throw new TypeError(`Sim CloudFormation Fn::Join values must each resolve to a string, got ${typeof resolved}`);
63
+ return this.values.referencedNames();
58
64
  }
59
65
  /**
60
- * Whether a resolved value is still an unresolved intrinsic expression.
66
+ * Refuse a value that can never become a string.
61
67
  *
62
- * Only object-shaped values (a preserved `Ref` or nested function object)
63
- * are treated as deferred. Other non-string primitives such as numbers are
64
- * genuine type errors.
68
+ * A string joins now, and an unresolved expression may join on a later
69
+ * pass. Anything else (a number, a nested list, a plain object) is a type
70
+ * error, as CloudFormation joins a list of strings only.
65
71
  */
66
- isDeferredExpression(value) {
67
- return typeof value === "object" && value !== null;
72
+ assertJoinable(value) {
73
+ if (typeof value === "string" || isSimCfnUnresolvedExpression(value)) {
74
+ return;
75
+ }
76
+ throw new TypeError(`Sim CloudFormation Fn::Join values must each resolve to a string, got ${describe(value)}`);
77
+ }
78
+ }
79
+ /**
80
+ * Name a resolved value's type for an error message, telling a list and a
81
+ * null apart from an object.
82
+ */
83
+ function describe(value) {
84
+ if (Array.isArray(value)) {
85
+ return "list";
68
86
  }
87
+ return value === null ? "null" : typeof value;
69
88
  }
@@ -10,10 +10,13 @@ import type { SimCfnValueParser } from "../../value/sim-cfn-value-parser.type.js
10
10
  * "Fn::Join": ["-", ["a", { "Ref": "Name" }]]
11
11
  * }
12
12
  *
13
- * The parser validates only the Fn::Join envelope: a string delimiter and an
14
- * array of values. Each joined value is parsed through the recursive value
15
- * parser, because join entries may themselves be literals, Refs, other
16
- * intrinsic functions, arrays, or plain objects.
13
+ * The values argument goes through the recursive value parser. It may be a
14
+ * literal list, whose entries may themselves be literals, Refs or other
15
+ * intrinsic functions, or a function that returns a whole list (such as
16
+ * `Fn::GetAtt` on a hosted zone's `NameServers`, or `Fn::Split`). Whether it
17
+ * resolves to a list of strings is a resolution-time question, so it belongs
18
+ * to the node. A string, number or boolean in its place can never become a
19
+ * list, and is refused here.
17
20
  */
18
21
  export declare class SimCfnFnJoinParser {
19
22
  private readonly valueParser;
@@ -8,10 +8,13 @@ import { SimCfnFnJoin as SimCfnFunctionJoin } from "../../../node/fn/join/sim-cf
8
8
  * "Fn::Join": ["-", ["a", { "Ref": "Name" }]]
9
9
  * }
10
10
  *
11
- * The parser validates only the Fn::Join envelope: a string delimiter and an
12
- * array of values. Each joined value is parsed through the recursive value
13
- * parser, because join entries may themselves be literals, Refs, other
14
- * intrinsic functions, arrays, or plain objects.
11
+ * The values argument goes through the recursive value parser. It may be a
12
+ * literal list, whose entries may themselves be literals, Refs or other
13
+ * intrinsic functions, or a function that returns a whole list (such as
14
+ * `Fn::GetAtt` on a hosted zone's `NameServers`, or `Fn::Split`). Whether it
15
+ * resolves to a list of strings is a resolution-time question, so it belongs
16
+ * to the node. A string, number or boolean in its place can never become a
17
+ * list, and is refused here.
15
18
  */
16
19
  export class SimCfnFnJoinParser {
17
20
  valueParser;
@@ -29,9 +32,10 @@ export class SimCfnFnJoinParser {
29
32
  if (typeof delimiter !== "string") {
30
33
  throw new TypeError("Sim CloudFormation Fn::Join delimiter must be a string");
31
34
  }
32
- if (!Array.isArray(values)) {
33
- throw new TypeError("Sim CloudFormation Fn::Join values must be an array");
35
+ if (typeof values !== "object" || values === null) {
36
+ throw new TypeError("Sim CloudFormation Fn::Join values must be a list or a function " +
37
+ "that returns one");
34
38
  }
35
- return new SimCfnFunctionJoin(delimiter, values.map((item) => this.valueParser.parse(item)));
39
+ return new SimCfnFunctionJoin(delimiter, this.valueParser.parse(values));
36
40
  }
37
41
  }
@@ -415,6 +415,6 @@ service guide lists its supported commands.
415
415
  - `yulin watch` does not preserve simulated state across a restart or reload changed Lambda and
416
416
  CloudFront Function code inside the current process.
417
417
  - The shared AWS API endpoint refuses unsupported protocols and operations with `501 Not
418
- Implemented`.
418
+ Implemented`.
419
419
  - Some service functionality is available only through `SimAws` or SDK interception. Check the
420
420
  relevant service guide before depending on access through the local endpoint.
@@ -948,8 +948,20 @@ console.log(
948
948
 
949
949
  A parameter with no supplied value takes the template default, when the template has one.
950
950
 
951
- A parameter's `Type` is read for the `AWS::SSM::Parameter::Value<...>` types, which hold a Parameter
952
- Store name and resolve to the value stored under it. See
951
+ A `CommaDelimitedList` or `List<...>` parameter (`List<String>`, `List<Number>`,
952
+ `List<AWS::EC2::Subnet::Id>` and the rest) is given one comma-separated string. A `Ref` to it
953
+ resolves to the list of members, each trimmed of the spaces around it. `Fn::Join` and `Fn::Select`
954
+ read that list as they read any other:
955
+
956
+ ```json
957
+ { "Fn::Join": ["-", { "Ref": "Names" }] }
958
+ ```
959
+
960
+ With `Names` declared as a `CommaDelimitedList` and given `a, b, c`, this resolves to `a-b-c`. The
961
+ members of a `List<Number>` are strings, as CloudFormation gives them.
962
+
963
+ The `AWS::SSM::Parameter::Value<...>` types hold a Parameter Store name and resolve to the value
964
+ stored under it. See
953
965
  [reading a parameter through a template Parameter](https://yulinsim.dev/services/ssm/#reading-a-parameter-through-a-template-parameter).
954
966
  Every other type is accepted and its value used as written, with no validation of the value against
955
967
  the type.
@@ -1217,6 +1229,17 @@ await simAws.cloudFormation().deployTemplate({
1217
1229
  });
1218
1230
  ```
1219
1231
 
1232
+ The second argument may also be a function that returns the whole list. CDK writes this for
1233
+ `Fn.join(",", zone.hostedZoneNameServers)`:
1234
+
1235
+ ```json
1236
+ { "Fn::Join": [",", { "Fn::GetAtt": ["Zone", "NameServers"] }] }
1237
+ ```
1238
+
1239
+ `Fn::Split`, an `Fn::FindInMap` of a list value, `Fn::If` and a `Ref` to a list parameter can supply
1240
+ the list the same way. A list that resolves to anything but strings fails the deployment. That
1241
+ includes a number, and a list nested inside the list (CloudFormation joins one level only).
1242
+
1220
1243
  ### `Fn::Sub`
1221
1244
 
1222
1245
  ```typescript sim-cloudformation-fn-sub
@@ -4545,9 +4568,9 @@ Each service's own docs describe what its resource types support.
4545
4568
  would reject as well. The simulator just rejects them later rather than up front.
4546
4569
  - `Fn::If` is a condition function inside the `Conditions` section, and is not a value an
4547
4570
  `Fn::Equals` can compare. Real CloudFormation allows only `Ref` and `Fn::FindInMap` there.
4548
- - `Fn::Split` and `Fn::Select` accept any argument that resolves to the type they need. Real
4549
- CloudFormation allows only a named set of functions inside each of them. A template the simulator
4550
- resolves may still be one CloudFormation rejects.
4571
+ - `Fn::Join`, `Fn::Split` and `Fn::Select` accept any argument that resolves to the type they
4572
+ need. Real CloudFormation allows only a named set of functions inside each of them. A template the
4573
+ simulator resolves may still be one CloudFormation rejects.
4551
4574
  - The SAM transform is expanded for `AWS::Serverless::Function`, `AWS::Serverless::SimpleTable`,
4552
4575
  `AWS::Serverless::HttpApi` and `AWS::Serverless::Api`. Every other `AWS::Serverless::*` resource
4553
4576
  type is recorded as unsupported. `Api`, `HttpApi`, `SQS`, `DynamoDB`, `SNS`, `S3`, `Cognito`,
@@ -3940,7 +3940,7 @@ is written.
3940
3940
  `AWS::DynamoDB::Table` path does, with the replica's `TableClass`, `DeletionProtectionEnabled` and
3941
3941
  `Tags` read off it, the table's writes and the replica's reads put back together into one
3942
3942
  provisioned capacity for the table and for each global secondary index, and `Ref`, `Fn::GetAtt …
3943
- Arn`, `Fn::GetAtt … StreamArn` and `Fn::GetAtt … TableId` answering. A CDK `TableV2` stack deploys
3943
+ Arn`, `Fn::GetAtt … StreamArn` and `Fn::GetAtt … TableId` answering. A CDK `TableV2` stack deploys
3944
3944
  through it without hand-editing.
3945
3945
  - SDK interception, and an intercepted `DynamoDBClient` or `DynamoDBStreamsClient` reaches the
3946
3946
  simulation.
@@ -4035,7 +4035,7 @@ Arn`, `Fn::GetAtt … StreamArn` and `Fn::GetAtt … TableId` answering. A CDK `
4035
4035
  - Time to live expiry is dispatched by moving the clock through `simAws.clock()`, not by real time
4036
4036
  elapsing. An item whose window goes by while a running-mode clock tracks the host stays where it
4037
4037
  is until something moves the clock. A simulated DynamoDB constructed standalone as `new
4038
- SimDynamoDb()` has no clock control at all. No item there ever expires.
4038
+ SimDynamoDb()` has no clock control at all. No item there ever expires.
4039
4039
  - A Lambda event source mapping is the only simulated service integration that consumes a stream.
4040
4040
  Anything else reads one through the Streams API itself. A Kinesis Data Streams destination is
4041
4041
  absent.
@@ -1079,7 +1079,7 @@ A delete on a versioned Bucket raises `s3:ObjectRemoved:DeleteMarkerCreated` rat
1079
1079
 
1080
1080
  - MFA delete is refused with `NotImplemented` rather than stored. Nothing here could enforce it, and
1081
1081
  a Bucket reporting a protection it does not apply is worse than one that says so. `MFADelete:
1082
- "Disabled"` is taken, and any other value is refused with `InvalidArgument`.
1082
+ "Disabled"` is taken, and any other value is refused with `InvalidArgument`.
1083
1083
  - A `versionId` in a `CopySource` is still refused with `NotImplemented`. A copy reads the current
1084
1084
  version.
1085
1085
  - `NoncurrentVersionTransitions` is stored and unread, because storage classes are left out. An
@@ -1214,7 +1214,7 @@ Current documented limitations:
1214
1214
  - A Lambda event source mapping polls one batch at a time. Real Lambda runs several pollers at once
1215
1215
  and scales them with the queue, and what that concurrency does to ordering is invisible here. See
1216
1216
  [simulated Lambda](https://yulinsim.dev/services/lambda/#triggering-a-function-from-an-sqs-queue "Simulated Lambda event
1217
- source mapping docs") for the rest of the mapping limitations.
1217
+ source mapping docs") for the rest of the mapping limitations.
1218
1218
  - `AWS::SQS::Queue` and `AWS::SQS::QueuePolicy` are the SQS resource types CloudFormation creates.
1219
1219
  Any other is reported as unsupported and skipped. A queue attribute outside the range real SQS
1220
1220
  accepts fails the resource, and a property it has no behaviour for is recorded and the queue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/yulin",
3
- "version": "1.21.27",
3
+ "version": "1.21.28",
4
4
  "description": "AWS system behaviour simulation for isolated unit testing",
5
5
  "repository": "https://github.com/KensioSoftware/yulin",
6
6
  "homepage": "https://yulinsim.dev/",
@@ -299,7 +299,7 @@
299
299
  "hyparquet": "^1.29.2",
300
300
  "hyparquet-writer": "^0.16.9",
301
301
  "node-sql-parser": "^5.4.0",
302
- "oxfmt": "^0.71.0",
302
+ "oxfmt": "^0.72.0",
303
303
  "oxlint": "^1.77.0",
304
304
  "oxlint-tsgolint": "^7.0.2001",
305
305
  "semantic-release": "25.0.9",