@brytdesigns/shopify-utils 3.0.0 → 3.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.
@@ -1,3 +1,4 @@
1
+ import { FiniteFromNumericString } from "../Schemas/index.js";
1
2
  import * as Schema from "effect/Schema";
2
3
  //#region src/effect/Resource/schema.ts
3
4
  var Type = Schema.Literals([
@@ -38,7 +39,7 @@ var Type = Schema.Literals([
38
39
  var GID = Schema.String.check(Schema.isStartingWith("gid://shopify/"));
39
40
  var ID = Schema.Union([
40
41
  Schema.Number,
41
- Schema.NumberFromString,
42
+ FiniteFromNumericString,
42
43
  Schema.String
43
44
  ]);
44
45
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../../src/effect/Resource/schema.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\n\nexport type Type = Schema.Schema.Type<typeof Type>;\nexport const Type = Schema.Literals([\n\t\"Cart\",\n\t\"Collection\",\n\t\"Customer\",\n\t\"DeliveryCarrierService\",\n\t\"DeliveryLocationGroup\",\n\t\"DeliveryProfile\",\n\t\"DeliveryZone\",\n\t\"DraftOrder\",\n\t\"DraftOrderLineItem\",\n\t\"Duty\",\n\t\"EmailTemplate\",\n\t\"Fulfillment\",\n\t\"FulfullmentEvent\",\n\t\"FullfullmentService\",\n\t\"InventoryItem\",\n\t\"InventoryLevel\",\n\t\"LineItem\",\n\t\"Location\",\n\t\"MarketingEvent\",\n\t\"MediaImage\",\n\t\"Metafield\",\n\t\"OnlineStoreArticle\",\n\t\"OnlineStoreBlog\",\n\t\"OnlineStorePage\",\n\t\"Order\",\n\t\"OrderTransaction\",\n\t\"Product\",\n\t\"ProductImage\",\n\t\"ProductVariant\",\n\t\"Refund\",\n\t\"Shop\",\n\t\"StaffMember\",\n\t\"Theme\",\n]);\n\nexport type GID = Schema.Codec.Encoded<typeof GID>;\nexport const GID = Schema.String.check(Schema.isStartingWith(\"gid://shopify/\"));\n\nexport type ID = Schema.Codec.Encoded<typeof ID>;\nexport const ID = Schema.Union([\n\tSchema.Number,\n\tSchema.NumberFromString,\n\tSchema.String,\n]);\n"],"mappings":";;AAGA,IAAa,OAAO,OAAO,SAAS;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AAGD,IAAa,MAAM,OAAO,OAAO,MAAM,OAAO,eAAe,gBAAgB,CAAC;AAG9E,IAAa,KAAK,OAAO,MAAM;CAC9B,OAAO;CACP,OAAO;CACP,OAAO;AACR,CAAC"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../src/effect/Resource/schema.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as Schemas from \"../Schemas/index.js\";\n\nexport type Type = Schema.Schema.Type<typeof Type>;\nexport const Type = Schema.Literals([\n\t\"Cart\",\n\t\"Collection\",\n\t\"Customer\",\n\t\"DeliveryCarrierService\",\n\t\"DeliveryLocationGroup\",\n\t\"DeliveryProfile\",\n\t\"DeliveryZone\",\n\t\"DraftOrder\",\n\t\"DraftOrderLineItem\",\n\t\"Duty\",\n\t\"EmailTemplate\",\n\t\"Fulfillment\",\n\t\"FulfullmentEvent\",\n\t\"FullfullmentService\",\n\t\"InventoryItem\",\n\t\"InventoryLevel\",\n\t\"LineItem\",\n\t\"Location\",\n\t\"MarketingEvent\",\n\t\"MediaImage\",\n\t\"Metafield\",\n\t\"OnlineStoreArticle\",\n\t\"OnlineStoreBlog\",\n\t\"OnlineStorePage\",\n\t\"Order\",\n\t\"OrderTransaction\",\n\t\"Product\",\n\t\"ProductImage\",\n\t\"ProductVariant\",\n\t\"Refund\",\n\t\"Shop\",\n\t\"StaffMember\",\n\t\"Theme\",\n]);\n\nexport type GID = Schema.Codec.Encoded<typeof GID>;\nexport const GID = Schema.String.check(Schema.isStartingWith(\"gid://shopify/\"));\n\n/**\n * A Shopify id: a number, a numeric string decoded to one, or any other\n * string left as it is - a line item key, a handle, an empty string.\n *\n * The middle member was `Schema.NumberFromString`, which in Effect 4 never\n * fails, so `String` was unreachable and every non-numeric id decoded to NaN.\n * See `Schemas.FiniteFromNumericString`.\n */\nexport type ID = Schema.Codec.Encoded<typeof ID>;\nexport const ID = Schema.Union([\n\tSchema.Number,\n\tSchemas.FiniteFromNumericString,\n\tSchema.String,\n]);\n"],"mappings":";;;AAIA,IAAa,OAAO,OAAO,SAAS;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AAGD,IAAa,MAAM,OAAO,OAAO,MAAM,OAAO,eAAe,gBAAgB,CAAC;AAW9E,IAAa,KAAK,OAAO,MAAM;CAC9B,OAAO;CACP;CACA,OAAO;AACR,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Schema from "effect/Schema";
4
+ import * as SchemaIssue from "effect/SchemaIssue";
5
+ import * as Arr from "effect/Array";
6
+ import * as Option from "effect/Option";
7
+ import * as SchemaParser from "effect/SchemaParser";
8
+ import * as SchemaTransformation from "effect/SchemaTransformation";
9
+ //#region src/effect/Schemas/index.ts
10
+ var Schemas_exports = /* @__PURE__ */ __exportAll({
11
+ ArrayDroppingInvalid: () => ArrayDroppingInvalid,
12
+ FiniteFromNumericString: () => FiniteFromNumericString
13
+ });
14
+ var formatIssue = SchemaIssue.makeFormatterDefault();
15
+ /**
16
+ * An array that decodes element by element and drops the elements that fail.
17
+ *
18
+ * `Schema.Array` fails the whole array on its first bad element, which is right
19
+ * for a request body and wrong for a list of search results: one product with a
20
+ * malformed price would reject every product, collection and page around it.
21
+ * This keeps the rest.
22
+ *
23
+ * Built with `declareConstructor` rather than `Schema.Array(item.pipe(
24
+ * Schema.catchDecoding(...)))`. Recovering to `Option.none()` inside an array
25
+ * does not drop the element: v4's array parser reports a missing element as a
26
+ * `MissingKey` issue, so the array fails anyway. A declaration owns the whole
27
+ * array and can leave elements out.
28
+ *
29
+ * The type is `ReadonlyArray<Type>`, identical to `Schema.Array`'s, so a
30
+ * schema can switch to this without changing what it decodes to. Input that is
31
+ * not an array at all still fails: that is a broken response, not a bad item.
32
+ *
33
+ * Each dropped element is logged at `Debug` with its index and the issue, so
34
+ * it is visible wherever the caller has turned debug logging on and silent
35
+ * everywhere else.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { Schemas } from "@brytdesigns/shopify-utils/effect";
40
+ *
41
+ * const Results = Schema.Struct({
42
+ * products: Schemas.ArrayDroppingInvalid(Product),
43
+ * });
44
+ * ```
45
+ */
46
+ var ArrayDroppingInvalid = (item) => Schema.declareConstructor()([item], ([codec]) => {
47
+ const decode = SchemaParser.decodeUnknownEffect(codec);
48
+ return (input, ast, options) => {
49
+ if (!Array.isArray(input)) return Effect.fail(new SchemaIssue.InvalidType(ast, input, options));
50
+ return Effect.forEach(input, (element, index) => decode(element, options).pipe(Effect.map(Option.some), Effect.catch((issue) => Effect.logDebug("Dropped an array element that failed to decode", {
51
+ index,
52
+ issue: formatIssue(issue)
53
+ }).pipe(Effect.as(Option.none()))))).pipe(Effect.map(Arr.getSomes));
54
+ };
55
+ });
56
+ /**
57
+ * A string holding a number, decoded to that number. Anything else fails.
58
+ *
59
+ * What Effect 3's `Schema.NumberFromString` was, and Effect 4's is not. v4's
60
+ * is plain `Number(s)` and never fails: "abc" decodes to NaN, and "" and
61
+ * whitespace to 0. `Schema.FiniteFromString` rejects NaN and Infinity but
62
+ * still reads a blank string as 0. Neither is safe in a union whose later
63
+ * members are meant to catch what the numeric one refuses, and neither should
64
+ * turn a missing price into a free product.
65
+ *
66
+ * Accepts what v3 accepted, minus the non-finite values: a string with at
67
+ * least one non-whitespace character that `Number()` reads as finite. So
68
+ * `"10.00"` is 10, `" 42 "` is 42, and `""`, `" "`, `"abc"` and `"NaN"`
69
+ * fail.
70
+ */
71
+ var FiniteFromNumericString = Schema.String.check(Schema.isPattern(/\S/, { expected: "a non-blank string" })).pipe(Schema.decodeTo(Schema.Finite, SchemaTransformation.numberFromString));
72
+ //#endregion
73
+ export { ArrayDroppingInvalid, FiniteFromNumericString, Schemas_exports };
74
+
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/effect/Schemas/index.ts"],"sourcesContent":["import * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport * as SchemaTransformation from \"effect/SchemaTransformation\";\n\nconst formatIssue = SchemaIssue.makeFormatterDefault();\n\n/**\n * An array that decodes element by element and drops the elements that fail.\n *\n * `Schema.Array` fails the whole array on its first bad element, which is right\n * for a request body and wrong for a list of search results: one product with a\n * malformed price would reject every product, collection and page around it.\n * This keeps the rest.\n *\n * Built with `declareConstructor` rather than `Schema.Array(item.pipe(\n * Schema.catchDecoding(...)))`. Recovering to `Option.none()` inside an array\n * does not drop the element: v4's array parser reports a missing element as a\n * `MissingKey` issue, so the array fails anyway. A declaration owns the whole\n * array and can leave elements out.\n *\n * The type is `ReadonlyArray<Type>`, identical to `Schema.Array`'s, so a\n * schema can switch to this without changing what it decodes to. Input that is\n * not an array at all still fails: that is a broken response, not a bad item.\n *\n * Each dropped element is logged at `Debug` with its index and the issue, so\n * it is visible wherever the caller has turned debug logging on and silent\n * everywhere else.\n *\n * @example\n * ```ts\n * import { Schemas } from \"@brytdesigns/shopify-utils/effect\";\n *\n * const Results = Schema.Struct({\n * products: Schemas.ArrayDroppingInvalid(Product),\n * });\n * ```\n */\nexport const ArrayDroppingInvalid = <S extends Schema.Constraint>(item: S) =>\n\tSchema.declareConstructor<\n\t\tReadonlyArray<S[\"Type\"]>,\n\t\tReadonlyArray<S[\"Encoded\"]>\n\t>()([item], ([codec]) => {\n\t\tconst decode = SchemaParser.decodeUnknownEffect(codec);\n\n\t\treturn (input, ast, options) => {\n\t\t\tif (!Array.isArray(input)) {\n\t\t\t\treturn Effect.fail(new SchemaIssue.InvalidType(ast, input, options));\n\t\t\t}\n\n\t\t\treturn Effect.forEach(input, (element, index) =>\n\t\t\t\tdecode(element, options).pipe(\n\t\t\t\t\tEffect.map(Option.some),\n\t\t\t\t\tEffect.catch((issue) =>\n\t\t\t\t\t\tEffect.logDebug(\"Dropped an array element that failed to decode\", {\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tissue: formatIssue(issue),\n\t\t\t\t\t\t}).pipe(Effect.as(Option.none())),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t).pipe(Effect.map(Arr.getSomes));\n\t\t};\n\t});\n\n/**\n * A string holding a number, decoded to that number. Anything else fails.\n *\n * What Effect 3's `Schema.NumberFromString` was, and Effect 4's is not. v4's\n * is plain `Number(s)` and never fails: \"abc\" decodes to NaN, and \"\" and\n * whitespace to 0. `Schema.FiniteFromString` rejects NaN and Infinity but\n * still reads a blank string as 0. Neither is safe in a union whose later\n * members are meant to catch what the numeric one refuses, and neither should\n * turn a missing price into a free product.\n *\n * Accepts what v3 accepted, minus the non-finite values: a string with at\n * least one non-whitespace character that `Number()` reads as finite. So\n * `\"10.00\"` is 10, `\" 42 \"` is 42, and `\"\"`, `\" \"`, `\"abc\"` and `\"NaN\"`\n * fail.\n */\nexport const FiniteFromNumericString = Schema.String.check(\n\tSchema.isPattern(/\\S/, { expected: \"a non-blank string\" }),\n).pipe(Schema.decodeTo(Schema.Finite, SchemaTransformation.numberFromString));\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAM,cAAc,YAAY,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCrD,IAAa,wBAAqD,SACjE,OAAO,mBAGL,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW;CACxB,MAAM,SAAS,aAAa,oBAAoB,KAAK;CAErD,QAAQ,OAAO,KAAK,YAAY;EAC/B,IAAI,CAAC,MAAM,QAAQ,KAAK,GACvB,OAAO,OAAO,KAAK,IAAI,YAAY,YAAY,KAAK,OAAO,OAAO,CAAC;EAGpE,OAAO,OAAO,QAAQ,QAAQ,SAAS,UACtC,OAAO,SAAS,OAAO,CAAC,CAAC,KACxB,OAAO,IAAI,OAAO,IAAI,GACtB,OAAO,OAAO,UACb,OAAO,SAAS,kDAAkD;GACjE;GACA,OAAO,YAAY,KAAK;EACzB,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,OAAO,KAAK,CAAC,CAAC,CACjC,CACD,CACD,CAAC,CAAC,KAAK,OAAO,IAAI,IAAI,QAAQ,CAAC;CAChC;AACD,CAAC;;;;;;;;;;;;;;;;AAiBF,IAAa,0BAA0B,OAAO,OAAO,MACpD,OAAO,UAAU,MAAM,EAAE,UAAU,qBAAqB,CAAC,CAC1D,CAAC,CAAC,KAAK,OAAO,SAAS,OAAO,QAAQ,qBAAqB,gBAAgB,CAAC"}
@@ -394,10 +394,18 @@ declare const Type: Schema.Literals<readonly [
394
394
  ]>;
395
395
  export type GID = Schema.Codec.Encoded<typeof GID>;
396
396
  declare const GID: Schema.String;
397
+ /**
398
+ * A Shopify id: a number, a numeric string decoded to one, or any other
399
+ * string left as it is - a line item key, a handle, an empty string.
400
+ *
401
+ * The middle member was `Schema.NumberFromString`, which in Effect 4 never
402
+ * fails, so `String` was unreachable and every non-numeric id decoded to NaN.
403
+ * See `Schemas.FiniteFromNumericString`.
404
+ */
397
405
  export type ID = Schema.Codec.Encoded<typeof ID>;
398
406
  declare const ID: Schema.Union<readonly [
399
407
  Schema.Number,
400
- Schema.NumberFromString,
408
+ Schema.decodeTo<Schema.Finite, Schema.String, never, never>,
401
409
  Schema.String
402
410
  ]>;
403
411
  export type FormatOptions<T extends ID, R extends Type> = {
@@ -406,12 +414,16 @@ export type FormatOptions<T extends ID, R extends Type> = {
406
414
  };
407
415
  declare const format: <const T extends ID, const R extends Type>({ id, type, }: FormatOptions<T, R>) => Effect.Effect<`gid://shopify/${R}/${T}`, Schema.SchemaError, never>;
408
416
  declare const parse: (input: string) => Effect.Effect<string | number, Schema.SchemaError, never>;
417
+ declare const ArrayDroppingInvalid: <S extends Schema.Constraint>(item: S) => Schema.declareConstructor<readonly S["Type"][], readonly S["Encoded"][], readonly [
418
+ S
419
+ ], readonly S["Type"][]>;
420
+ declare const FiniteFromNumericString: Schema.decodeTo<Schema.Finite, Schema.String, never, never>;
409
421
 
410
422
  declare namespace Bridge {
411
423
  export { fromPromiseThunk, toAsyncCallback, toSyncCallback };
412
424
  }
413
- declare namespace Resource {
414
- export { GID, ID, Type, format, parse };
425
+ declare namespace Schemas {
426
+ export { ArrayDroppingInvalid, FiniteFromNumericString };
415
427
  }
416
428
  declare namespace Sections {
417
429
  export { Input, makeResponseSchema };
@@ -440,12 +452,16 @@ declare namespace Ajax {
440
452
  declare namespace Logging {
441
453
  export { filterLevelOrNever, makeNamespacedLogSpan };
442
454
  }
455
+ declare namespace Resource {
456
+ export { GID, ID, Type, format, parse };
457
+ }
443
458
 
444
459
  export {
445
460
  Actions,
446
461
  Ajax,
447
462
  Logging,
448
463
  Resource,
464
+ Schemas,
449
465
  };
450
466
 
451
467
  export {};
@@ -1,5 +1,6 @@
1
1
  import { Actions_exports } from "./Actions/index.js";
2
2
  import { Ajax_exports } from "./Ajax/index.js";
3
3
  import { Logging_exports } from "./Logging/index.js";
4
+ import { Schemas_exports } from "./Schemas/index.js";
4
5
  import { Resource_exports } from "./Resource/index.js";
5
- export { Actions_exports as Actions, Ajax_exports as Ajax, Logging_exports as Logging, Resource_exports as Resource };
6
+ export { Actions_exports as Actions, Ajax_exports as Ajax, Logging_exports as Logging, Resource_exports as Resource, Schemas_exports as Schemas };
@@ -1,3 +1,4 @@
1
+ import { FiniteFromNumericString } from "../Schemas/index.js";
1
2
  import * as Schema from "effect/Schema";
2
3
  //#region src/effect/Resource/schema.ts
3
4
  var Type = Schema.Literals([
@@ -38,7 +39,7 @@ var Type = Schema.Literals([
38
39
  var GID = Schema.String.check(Schema.isStartingWith("gid://shopify/"));
39
40
  var ID = Schema.Union([
40
41
  Schema.Number,
41
- Schema.NumberFromString,
42
+ FiniteFromNumericString,
42
43
  Schema.String
43
44
  ]);
44
45
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../../../src/effect/Resource/schema.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\n\nexport type Type = Schema.Schema.Type<typeof Type>;\nexport const Type = Schema.Literals([\n\t\"Cart\",\n\t\"Collection\",\n\t\"Customer\",\n\t\"DeliveryCarrierService\",\n\t\"DeliveryLocationGroup\",\n\t\"DeliveryProfile\",\n\t\"DeliveryZone\",\n\t\"DraftOrder\",\n\t\"DraftOrderLineItem\",\n\t\"Duty\",\n\t\"EmailTemplate\",\n\t\"Fulfillment\",\n\t\"FulfullmentEvent\",\n\t\"FullfullmentService\",\n\t\"InventoryItem\",\n\t\"InventoryLevel\",\n\t\"LineItem\",\n\t\"Location\",\n\t\"MarketingEvent\",\n\t\"MediaImage\",\n\t\"Metafield\",\n\t\"OnlineStoreArticle\",\n\t\"OnlineStoreBlog\",\n\t\"OnlineStorePage\",\n\t\"Order\",\n\t\"OrderTransaction\",\n\t\"Product\",\n\t\"ProductImage\",\n\t\"ProductVariant\",\n\t\"Refund\",\n\t\"Shop\",\n\t\"StaffMember\",\n\t\"Theme\",\n]);\n\nexport type GID = Schema.Codec.Encoded<typeof GID>;\nexport const GID = Schema.String.check(Schema.isStartingWith(\"gid://shopify/\"));\n\nexport type ID = Schema.Codec.Encoded<typeof ID>;\nexport const ID = Schema.Union([\n\tSchema.Number,\n\tSchema.NumberFromString,\n\tSchema.String,\n]);\n"],"mappings":";;AAGA,IAAa,OAAO,OAAO,SAAS;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AAGD,IAAa,MAAM,OAAO,OAAO,MAAM,OAAO,eAAe,gBAAgB,CAAC;AAG9E,IAAa,KAAK,OAAO,MAAM;CAC9B,OAAO;CACP,OAAO;CACP,OAAO;AACR,CAAC"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../../src/effect/Resource/schema.ts"],"sourcesContent":["import * as Schema from \"effect/Schema\";\nimport * as Schemas from \"../Schemas/index.js\";\n\nexport type Type = Schema.Schema.Type<typeof Type>;\nexport const Type = Schema.Literals([\n\t\"Cart\",\n\t\"Collection\",\n\t\"Customer\",\n\t\"DeliveryCarrierService\",\n\t\"DeliveryLocationGroup\",\n\t\"DeliveryProfile\",\n\t\"DeliveryZone\",\n\t\"DraftOrder\",\n\t\"DraftOrderLineItem\",\n\t\"Duty\",\n\t\"EmailTemplate\",\n\t\"Fulfillment\",\n\t\"FulfullmentEvent\",\n\t\"FullfullmentService\",\n\t\"InventoryItem\",\n\t\"InventoryLevel\",\n\t\"LineItem\",\n\t\"Location\",\n\t\"MarketingEvent\",\n\t\"MediaImage\",\n\t\"Metafield\",\n\t\"OnlineStoreArticle\",\n\t\"OnlineStoreBlog\",\n\t\"OnlineStorePage\",\n\t\"Order\",\n\t\"OrderTransaction\",\n\t\"Product\",\n\t\"ProductImage\",\n\t\"ProductVariant\",\n\t\"Refund\",\n\t\"Shop\",\n\t\"StaffMember\",\n\t\"Theme\",\n]);\n\nexport type GID = Schema.Codec.Encoded<typeof GID>;\nexport const GID = Schema.String.check(Schema.isStartingWith(\"gid://shopify/\"));\n\n/**\n * A Shopify id: a number, a numeric string decoded to one, or any other\n * string left as it is - a line item key, a handle, an empty string.\n *\n * The middle member was `Schema.NumberFromString`, which in Effect 4 never\n * fails, so `String` was unreachable and every non-numeric id decoded to NaN.\n * See `Schemas.FiniteFromNumericString`.\n */\nexport type ID = Schema.Codec.Encoded<typeof ID>;\nexport const ID = Schema.Union([\n\tSchema.Number,\n\tSchemas.FiniteFromNumericString,\n\tSchema.String,\n]);\n"],"mappings":";;;AAIA,IAAa,OAAO,OAAO,SAAS;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;AAGD,IAAa,MAAM,OAAO,OAAO,MAAM,OAAO,eAAe,gBAAgB,CAAC;AAW9E,IAAa,KAAK,OAAO,MAAM;CAC9B,OAAO;CACP;CACA,OAAO;AACR,CAAC"}
@@ -0,0 +1,28 @@
1
+ import "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import * as SchemaIssue from "effect/SchemaIssue";
4
+ import "effect/Array";
5
+ import "effect/Option";
6
+ import "effect/SchemaParser";
7
+ import * as SchemaTransformation from "effect/SchemaTransformation";
8
+ SchemaIssue.makeFormatterDefault();
9
+ /**
10
+ * A string holding a number, decoded to that number. Anything else fails.
11
+ *
12
+ * What Effect 3's `Schema.NumberFromString` was, and Effect 4's is not. v4's
13
+ * is plain `Number(s)` and never fails: "abc" decodes to NaN, and "" and
14
+ * whitespace to 0. `Schema.FiniteFromString` rejects NaN and Infinity but
15
+ * still reads a blank string as 0. Neither is safe in a union whose later
16
+ * members are meant to catch what the numeric one refuses, and neither should
17
+ * turn a missing price into a free product.
18
+ *
19
+ * Accepts what v3 accepted, minus the non-finite values: a string with at
20
+ * least one non-whitespace character that `Number()` reads as finite. So
21
+ * `"10.00"` is 10, `" 42 "` is 42, and `""`, `" "`, `"abc"` and `"NaN"`
22
+ * fail.
23
+ */
24
+ var FiniteFromNumericString = Schema.String.check(Schema.isPattern(/\S/, { expected: "a non-blank string" })).pipe(Schema.decodeTo(Schema.Finite, SchemaTransformation.numberFromString));
25
+ //#endregion
26
+ export { FiniteFromNumericString };
27
+
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/effect/Schemas/index.ts"],"sourcesContent":["import * as Arr from \"effect/Array\";\nimport * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport * as SchemaTransformation from \"effect/SchemaTransformation\";\n\nconst formatIssue = SchemaIssue.makeFormatterDefault();\n\n/**\n * An array that decodes element by element and drops the elements that fail.\n *\n * `Schema.Array` fails the whole array on its first bad element, which is right\n * for a request body and wrong for a list of search results: one product with a\n * malformed price would reject every product, collection and page around it.\n * This keeps the rest.\n *\n * Built with `declareConstructor` rather than `Schema.Array(item.pipe(\n * Schema.catchDecoding(...)))`. Recovering to `Option.none()` inside an array\n * does not drop the element: v4's array parser reports a missing element as a\n * `MissingKey` issue, so the array fails anyway. A declaration owns the whole\n * array and can leave elements out.\n *\n * The type is `ReadonlyArray<Type>`, identical to `Schema.Array`'s, so a\n * schema can switch to this without changing what it decodes to. Input that is\n * not an array at all still fails: that is a broken response, not a bad item.\n *\n * Each dropped element is logged at `Debug` with its index and the issue, so\n * it is visible wherever the caller has turned debug logging on and silent\n * everywhere else.\n *\n * @example\n * ```ts\n * import { Schemas } from \"@brytdesigns/shopify-utils/effect\";\n *\n * const Results = Schema.Struct({\n * products: Schemas.ArrayDroppingInvalid(Product),\n * });\n * ```\n */\nexport const ArrayDroppingInvalid = <S extends Schema.Constraint>(item: S) =>\n\tSchema.declareConstructor<\n\t\tReadonlyArray<S[\"Type\"]>,\n\t\tReadonlyArray<S[\"Encoded\"]>\n\t>()([item], ([codec]) => {\n\t\tconst decode = SchemaParser.decodeUnknownEffect(codec);\n\n\t\treturn (input, ast, options) => {\n\t\t\tif (!Array.isArray(input)) {\n\t\t\t\treturn Effect.fail(new SchemaIssue.InvalidType(ast, input, options));\n\t\t\t}\n\n\t\t\treturn Effect.forEach(input, (element, index) =>\n\t\t\t\tdecode(element, options).pipe(\n\t\t\t\t\tEffect.map(Option.some),\n\t\t\t\t\tEffect.catch((issue) =>\n\t\t\t\t\t\tEffect.logDebug(\"Dropped an array element that failed to decode\", {\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tissue: formatIssue(issue),\n\t\t\t\t\t\t}).pipe(Effect.as(Option.none())),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t).pipe(Effect.map(Arr.getSomes));\n\t\t};\n\t});\n\n/**\n * A string holding a number, decoded to that number. Anything else fails.\n *\n * What Effect 3's `Schema.NumberFromString` was, and Effect 4's is not. v4's\n * is plain `Number(s)` and never fails: \"abc\" decodes to NaN, and \"\" and\n * whitespace to 0. `Schema.FiniteFromString` rejects NaN and Infinity but\n * still reads a blank string as 0. Neither is safe in a union whose later\n * members are meant to catch what the numeric one refuses, and neither should\n * turn a missing price into a free product.\n *\n * Accepts what v3 accepted, minus the non-finite values: a string with at\n * least one non-whitespace character that `Number()` reads as finite. So\n * `\"10.00\"` is 10, `\" 42 \"` is 42, and `\"\"`, `\" \"`, `\"abc\"` and `\"NaN\"`\n * fail.\n */\nexport const FiniteFromNumericString = Schema.String.check(\n\tSchema.isPattern(/\\S/, { expected: \"a non-blank string\" }),\n).pipe(Schema.decodeTo(Schema.Finite, SchemaTransformation.numberFromString));\n"],"mappings":";;;;;;;AAQoB,YAAY,qBAAqB;;;;;;;;;;;;;;;;AA0ErD,IAAa,0BAA0B,OAAO,OAAO,MACpD,OAAO,UAAU,MAAM,EAAE,UAAU,qBAAqB,CAAC,CAC1D,CAAC,CAAC,KAAK,OAAO,SAAS,OAAO,QAAQ,qBAAqB,gBAAgB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import "./Actions/index.js";
2
2
  import "./Ajax/index.js";
3
3
  import "./Logging/index.js";
4
+ import "./Schemas/index.js";
4
5
  import "./Resource/index.js";
@@ -342,10 +342,18 @@ declare const Type: Schema.Literals<readonly [
342
342
  ]>;
343
343
  export type GID = Schema.Codec.Encoded<typeof GID>;
344
344
  declare const GID: Schema.String;
345
+ /**
346
+ * A Shopify id: a number, a numeric string decoded to one, or any other
347
+ * string left as it is - a line item key, a handle, an empty string.
348
+ *
349
+ * The middle member was `Schema.NumberFromString`, which in Effect 4 never
350
+ * fails, so `String` was unreachable and every non-numeric id decoded to NaN.
351
+ * See `Schemas.FiniteFromNumericString`.
352
+ */
345
353
  export type ID = Schema.Codec.Encoded<typeof ID>;
346
354
  declare const ID: Schema.Union<readonly [
347
355
  Schema.Number,
348
- Schema.NumberFromString,
356
+ Schema.decodeTo<Schema.Finite, Schema.String, never, never>,
349
357
  Schema.String
350
358
  ]>;
351
359
  export type FormatOptions<T extends ID, R extends Type> = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brytdesigns/shopify-utils",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/main/index.js",