diff --git a/README.md b/README.md index 79e14cc..e154845 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,38 @@ const p: WithContext = { }; ``` +### Merging multiple concrete types + +Some Schema.org objects can legitimately carry multiple concrete `@type` values. +For those advanced cases, `schema-dts` exports leaf types alongside the usual +union aliases, plus a `MergeLeafTypes` helper for combining them: + +```ts +import type { + MergeLeafTypes, + ProductLeaf, + SoftwareApplicationLeaf, + WithContext, +} from 'schema-dts'; + +const product: WithContext< + MergeLeafTypes<[ProductLeaf, SoftwareApplicationLeaf]> +> = { + '@context': 'https://schema.org', + '@type': ['Product', 'SoftwareApplication'], + name: 'My App', + offers: { + '@type': 'Offer', + price: 89, + priceCurrency: 'USD', + }, + operatingSystem: 'Any', +}; +``` + +`MergeLeafTypes` expects concrete leaf types such as `ProductLeaf`, not union +aliases such as `Product`. + ### Graphs and IDs JSON-LD supports `'@graph'` objects that have richer interconnected links diff --git a/packages/schema-dts-gen/src/ts/class.ts b/packages/schema-dts-gen/src/ts/class.ts index 1a066f0..6b67baf 100644 --- a/packages/schema-dts-gen/src/ts/class.ts +++ b/packages/schema-dts-gen/src/ts/class.ts @@ -298,7 +298,7 @@ export class Class { assert(baseName, 'Expect baseName to exist when leafName exists.'); return factory.createInterfaceDeclaration( - /*modifiers=*/ [], + factory.createModifiersFromModifierFlags(ModifierFlags.Export), leafName, /*typeParameters=*/ [], /*heritage=*/ [ @@ -385,7 +385,7 @@ export class Class { // ... props; // }; // // Leaf: - // export type XyzLeaf = XyzBase & { + // export interface XyzLeaf extends XyzBase { // '@type': 'Xyz' // } // // Complete Type ----------------------------// @@ -496,7 +496,7 @@ export class RoleBuiltin extends Builtin { assert(baseName, 'Role must have Base Name.'); return factory.createTypeAliasDeclaration( - /*modifiers=*/ [], + factory.createModifiersFromModifierFlags(ModifierFlags.Export), leafName, /*typeParameters=*/ [ factory.createTypeParameterDeclaration( diff --git a/packages/schema-dts-gen/src/ts/helper_types.ts b/packages/schema-dts-gen/src/ts/helper_types.ts index eb0d262..0130a2b 100644 --- a/packages/schema-dts-gen/src/ts/helper_types.ts +++ b/packages/schema-dts-gen/src/ts/helper_types.ts @@ -73,6 +73,7 @@ function GraphType(context: Context) { } const SchemaValueName = 'SchemaValue'; +const MergeLeafTypesName = 'MergeLeafTypes'; export const IdReferenceName = 'IdReference'; export const GraphTypeName = 'Graph'; @@ -111,6 +112,11 @@ export function HelperTypes(context: Context, {hasRole}: {hasRole: boolean}) { /*propertyName=*/ undefined, /*name=*/ factory.createIdentifier('IdReference'), ), + factory.createImportSpecifier( + /*isTypeOnly=*/ false, + /*propertyName=*/ undefined, + /*name=*/ factory.createIdentifier(MergeLeafTypesName), + ), ]), ), factory.createStringLiteral('schema-dts-lib'), @@ -129,6 +135,11 @@ export function HelperTypes(context: Context, {hasRole}: {hasRole: boolean}) { /*propertyName=*/ undefined, /*name=*/ factory.createIdentifier('IdReference'), ), + factory.createExportSpecifier( + /*isTypeOnly=*/ false, + /*propertyName=*/ undefined, + /*name=*/ factory.createIdentifier(MergeLeafTypesName), + ), ]), ), WithContextType(context), diff --git a/packages/schema-dts-gen/test/baselines/category_test.ts b/packages/schema-dts-gen/test/baselines/category_test.ts index f02516b..e8b8a49 100644 --- a/packages/schema-dts-gen/test/baselines/category_test.ts +++ b/packages/schema-dts-gen/test/baselines/category_test.ts @@ -45,8 +45,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -67,7 +67,7 @@ export type WithActionConstraints = T & InputActionConstra export type Text = string; -interface DistilleryLeaf extends ThingBase { +export interface DistilleryLeaf extends ThingBase { "@type": "Distillery"; } /** A distillery. */ @@ -76,7 +76,7 @@ export type Distillery = DistilleryLeaf; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Distillery; diff --git a/packages/schema-dts-gen/test/baselines/comments_test.ts b/packages/schema-dts-gen/test/baselines/comments_test.ts index 3cd08cb..48ec033 100644 --- a/packages/schema-dts-gen/test/baselines/comments_test.ts +++ b/packages/schema-dts-gen/test/baselines/comments_test.ts @@ -65,8 +65,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -140,7 +140,7 @@ interface ThingBase extends Partial { */ "openingHours"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** diff --git a/packages/schema-dts-gen/test/baselines/data_type_union_test.ts b/packages/schema-dts-gen/test/baselines/data_type_union_test.ts index 1a973a9..d855f63 100644 --- a/packages/schema-dts-gen/test/baselines/data_type_union_test.ts +++ b/packages/schema-dts-gen/test/baselines/data_type_union_test.ts @@ -43,8 +43,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -74,7 +74,7 @@ interface ThingBase extends Partial { "age"?: SchemaValue; "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/default_ontology_test.ts b/packages/schema-dts-gen/test/baselines/default_ontology_test.ts index 2e75383..8d236e3 100644 --- a/packages/schema-dts-gen/test/baselines/default_ontology_test.ts +++ b/packages/schema-dts-gen/test/baselines/default_ontology_test.ts @@ -30,8 +30,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -52,7 +52,7 @@ export type WithActionConstraints = T & InputActionConstra interface ThingBase extends Partial { } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/deprecated_objects_test.ts b/packages/schema-dts-gen/test/baselines/deprecated_objects_test.ts index a994fdd..cf792a6 100644 --- a/packages/schema-dts-gen/test/baselines/deprecated_objects_test.ts +++ b/packages/schema-dts-gen/test/baselines/deprecated_objects_test.ts @@ -66,8 +66,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -93,7 +93,7 @@ export type Text = string; interface CarBase extends ThingBase { "doorNumber"?: SchemaValue; } -interface CarLeaf extends CarBase { +export interface CarLeaf extends CarBase { "@type": "Car"; } export type Car = CarLeaf; @@ -101,7 +101,7 @@ export type Car = CarLeaf; interface PersonLikeBase extends ThingBase { "height"?: SchemaValue; } -interface PersonLikeLeaf extends PersonLikeBase { +export interface PersonLikeLeaf extends PersonLikeBase { "@type": "PersonLike"; } export type PersonLike = PersonLikeLeaf; @@ -122,7 +122,7 @@ interface ThingBase extends Partial { */ "names2"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Car | PersonLike | Vehicle; @@ -132,7 +132,7 @@ interface VehicleBase extends ThingBase { /** @deprecated Consider using http://schema.org/doorNumber instead. */ "doors"?: SchemaValue; } -interface VehicleLeaf extends VehicleBase { +export interface VehicleLeaf extends VehicleBase { "@type": "Vehicle"; } /** @deprecated Use Car instead. */ diff --git a/packages/schema-dts-gen/test/baselines/duplicate_comments_test.ts b/packages/schema-dts-gen/test/baselines/duplicate_comments_test.ts index f2eb82b..54808b6 100644 --- a/packages/schema-dts-gen/test/baselines/duplicate_comments_test.ts +++ b/packages/schema-dts-gen/test/baselines/duplicate_comments_test.ts @@ -47,8 +47,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -76,7 +76,7 @@ interface ThingBase extends Partial { */ "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** diff --git a/packages/schema-dts-gen/test/baselines/enum_skipped_test.ts b/packages/schema-dts-gen/test/baselines/enum_skipped_test.ts index 613d217..232f80b 100644 --- a/packages/schema-dts-gen/test/baselines/enum_skipped_test.ts +++ b/packages/schema-dts-gen/test/baselines/enum_skipped_test.ts @@ -43,8 +43,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -65,7 +65,7 @@ export type WithActionConstraints = T & InputActionConstra interface ThingBase extends Partial { } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** A Thing! */ diff --git a/packages/schema-dts-gen/test/baselines/inheritance_multiple_test.ts b/packages/schema-dts-gen/test/baselines/inheritance_multiple_test.ts index 3033ef1..3a764e5 100644 --- a/packages/schema-dts-gen/test/baselines/inheritance_multiple_test.ts +++ b/packages/schema-dts-gen/test/baselines/inheritance_multiple_test.ts @@ -47,8 +47,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -74,7 +74,7 @@ export type Text = string; interface PersonLikeBase extends ThingBase { "height"?: SchemaValue; } -interface PersonLikeLeaf extends PersonLikeBase { +export interface PersonLikeLeaf extends PersonLikeBase { "@type": "PersonLike"; } export type PersonLike = PersonLikeLeaf; @@ -82,7 +82,7 @@ export type PersonLike = PersonLikeLeaf; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | PersonLike | Vehicle; @@ -90,7 +90,7 @@ export type Thing = ThingLeaf | PersonLike | Vehicle; interface VehicleBase extends ThingBase { "doors"?: SchemaValue; } -interface VehicleLeaf extends VehicleBase { +export interface VehicleLeaf extends VehicleBase { "@type": "Vehicle"; } export type Vehicle = VehicleLeaf; diff --git a/packages/schema-dts-gen/test/baselines/inheritance_one_test.ts b/packages/schema-dts-gen/test/baselines/inheritance_one_test.ts index 5e27291..98cdc69 100644 --- a/packages/schema-dts-gen/test/baselines/inheritance_one_test.ts +++ b/packages/schema-dts-gen/test/baselines/inheritance_one_test.ts @@ -42,8 +42,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -69,7 +69,7 @@ export type Text = string; interface PersonLikeBase extends ThingBase { "height"?: SchemaValue; } -interface PersonLikeLeaf extends PersonLikeBase { +export interface PersonLikeLeaf extends PersonLikeBase { "@type": "PersonLike"; } export type PersonLike = PersonLikeLeaf; @@ -77,7 +77,7 @@ export type PersonLike = PersonLikeLeaf; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | PersonLike; diff --git a/packages/schema-dts-gen/test/baselines/nested_datatype_test.ts b/packages/schema-dts-gen/test/baselines/nested_datatype_test.ts index 8f5857e..52c4f2f 100644 --- a/packages/schema-dts-gen/test/baselines/nested_datatype_test.ts +++ b/packages/schema-dts-gen/test/baselines/nested_datatype_test.ts @@ -57,8 +57,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -82,12 +82,12 @@ export type Text = PronounceableText | URL | string; interface ArabicTextBase extends PronounceableTextBase { "arabicPhoneticText"?: SchemaValue; } -interface ArabicTextLeaf extends ArabicTextBase { +export interface ArabicTextLeaf extends ArabicTextBase { "@type": "ArabicText"; } export type ArabicText = ArabicTextLeaf | string; -interface EnglishTextLeaf extends PronounceableTextBase { +export interface EnglishTextLeaf extends PronounceableTextBase { "@type": "EnglishText"; } export type EnglishText = EnglishTextLeaf | string; @@ -97,7 +97,7 @@ export type FancyURL = string; interface PronounceableTextBase extends Partial { "phoneticText"?: SchemaValue; } -interface PronounceableTextLeaf extends PronounceableTextBase { +export interface PronounceableTextLeaf extends PronounceableTextBase { "@type": "PronounceableText"; } export type PronounceableText = PronounceableTextLeaf | ArabicText | EnglishText | string; @@ -107,7 +107,7 @@ interface ThingBase extends Partial { "pronunciation"?: SchemaValue; "website"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/nodeprecated_objects_test.ts b/packages/schema-dts-gen/test/baselines/nodeprecated_objects_test.ts index f413b6a..7576941 100644 --- a/packages/schema-dts-gen/test/baselines/nodeprecated_objects_test.ts +++ b/packages/schema-dts-gen/test/baselines/nodeprecated_objects_test.ts @@ -65,8 +65,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -92,7 +92,7 @@ export type Text = string; interface CarBase extends ThingBase { "doorNumber"?: SchemaValue; } -interface CarLeaf extends CarBase { +export interface CarLeaf extends CarBase { "@type": "Car"; } export type Car = CarLeaf; @@ -100,7 +100,7 @@ export type Car = CarLeaf; interface PersonLikeBase extends ThingBase { "height"?: SchemaValue; } -interface PersonLikeLeaf extends PersonLikeBase { +export interface PersonLikeLeaf extends PersonLikeBase { "@type": "PersonLike"; } export type PersonLike = PersonLikeLeaf; @@ -108,7 +108,7 @@ export type PersonLike = PersonLikeLeaf; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Car | PersonLike; diff --git a/packages/schema-dts-gen/test/baselines/owl_mixed_basic_test.ts b/packages/schema-dts-gen/test/baselines/owl_mixed_basic_test.ts index 7d2b08d..6140fdf 100644 --- a/packages/schema-dts-gen/test/baselines/owl_mixed_basic_test.ts +++ b/packages/schema-dts-gen/test/baselines/owl_mixed_basic_test.ts @@ -41,8 +41,8 @@ test(`baseline_mixedOWL1_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -64,7 +64,7 @@ export type WithActionConstraints = T & InputActionConstra /** Data type: Text. */ export type Text = string; -interface PersonLeaf extends ThingBase { +export interface PersonLeaf extends ThingBase { "@type": "Person"; } /** ABC */ @@ -73,7 +73,7 @@ export type Person = PersonLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** ABC */ @@ -104,8 +104,8 @@ test(`baseline_mixedOWL2_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -127,7 +127,7 @@ export type WithActionConstraints = T & InputActionConstra /** Data type: Text. */ export type Text = string; -interface PersonLeaf extends ThingBase { +export interface PersonLeaf extends ThingBase { "@type": "Person"; } /** ABC */ @@ -136,7 +136,7 @@ export type Person = PersonLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** ABC */ @@ -172,8 +172,8 @@ test(`baseline_OWLenum_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -197,12 +197,12 @@ export type Text = string; interface www_w3_org_2002_07_owl_MyEnumBase extends Partial { } -interface www_w3_org_2002_07_owl_MyEnumLeaf extends www_w3_org_2002_07_owl_MyEnumBase { +export interface www_w3_org_2002_07_owl_MyEnumLeaf extends www_w3_org_2002_07_owl_MyEnumBase { "@type": "http://www.w3.org/2002/07/owl#MyEnum"; } export type www_w3_org_2002_07_owl_MyEnum = "http://www.w3.org/2002/07/owl#EnumValueA" | "https://www.w3.org/2002/07/owl#EnumValueA" | "http://www.w3.org/2002/07/owl#EnumValueB" | "https://www.w3.org/2002/07/owl#EnumValueB" | www_w3_org_2002_07_owl_MyEnumLeaf; -interface PersonLeaf extends ThingBase { +export interface PersonLeaf extends ThingBase { "@type": "Person"; } /** ABC */ @@ -211,7 +211,7 @@ export type Person = PersonLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** ABC */ diff --git a/packages/schema-dts-gen/test/baselines/property_edge_cases_test.ts b/packages/schema-dts-gen/test/baselines/property_edge_cases_test.ts index 24f02ef..5c97a78 100644 --- a/packages/schema-dts-gen/test/baselines/property_edge_cases_test.ts +++ b/packages/schema-dts-gen/test/baselines/property_edge_cases_test.ts @@ -42,8 +42,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -68,7 +68,7 @@ interface ThingBase extends Partial { "knows"?: SchemaValue; "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/quantities_test.ts b/packages/schema-dts-gen/test/baselines/quantities_test.ts index 2c38f24..db77a77 100644 --- a/packages/schema-dts-gen/test/baselines/quantities_test.ts +++ b/packages/schema-dts-gen/test/baselines/quantities_test.ts @@ -49,8 +49,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -69,34 +69,34 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface QuantityLeaf extends ThingBase { +export interface QuantityLeaf extends ThingBase { "@type": "Quantity"; } export type Quantity = QuantityLeaf | Distance | Duration | Energy | Mass | string; export type Text = string; -interface DistanceLeaf extends ThingBase { +export interface DistanceLeaf extends ThingBase { "@type": "Distance"; } export type Distance = DistanceLeaf | string; -interface DurationLeaf extends ThingBase { +export interface DurationLeaf extends ThingBase { "@type": "Duration"; } export type Duration = DurationLeaf | string; -interface EnergyLeaf extends ThingBase { +export interface EnergyLeaf extends ThingBase { "@type": "Energy"; } export type Energy = EnergyLeaf | string; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Quantity; -interface MassLeaf extends ThingBase { +export interface MassLeaf extends ThingBase { "@type": "Mass"; } export type Mass = MassLeaf | string; @@ -104,7 +104,7 @@ export type Mass = MassLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible; diff --git a/packages/schema-dts-gen/test/baselines/role_inheritance_test.ts b/packages/schema-dts-gen/test/baselines/role_inheritance_test.ts index 6b5db60..b9bb1cf 100644 --- a/packages/schema-dts-gen/test/baselines/role_inheritance_test.ts +++ b/packages/schema-dts-gen/test/baselines/role_inheritance_test.ts @@ -49,8 +49,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -71,12 +71,12 @@ export type WithActionConstraints = T & InputActionConstra interface DateTimeBase extends Partial { } -interface DateTimeLeaf extends DateTimeBase { +export interface DateTimeLeaf extends DateTimeBase { "@type": "DateTime"; } export type DateTime = DateTimeLeaf | string; -type OrganizationRoleLeaf = Omit & { +export type OrganizationRoleLeaf = Omit & { "@type": "OrganizationRole"; } & { [key in TProperty]: TContent; @@ -86,7 +86,7 @@ export type OrganizationRole interface RoleBase extends ThingBase { "startDate"?: SchemaValue; } -type RoleLeaf = Omit & { +export type RoleLeaf = Omit & { "@type": "Role"; } & { [key in TProperty]: TContent; @@ -100,7 +100,7 @@ export type Role = RoleLeaf< export type Text = string; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Role; @@ -108,7 +108,7 @@ export type Intangible = IntangibleLeaf | Role; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible; diff --git a/packages/schema-dts-gen/test/baselines/role_simple_test.ts b/packages/schema-dts-gen/test/baselines/role_simple_test.ts index 5cec9fe..6d6d550 100644 --- a/packages/schema-dts-gen/test/baselines/role_simple_test.ts +++ b/packages/schema-dts-gen/test/baselines/role_simple_test.ts @@ -46,8 +46,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -68,7 +68,7 @@ export type WithActionConstraints = T & InputActionConstra interface DateTimeBase extends Partial { } -interface DateTimeLeaf extends DateTimeBase { +export interface DateTimeLeaf extends DateTimeBase { "@type": "DateTime"; } export type DateTime = DateTimeLeaf | string; @@ -76,7 +76,7 @@ export type DateTime = DateTimeLeaf | string; interface RoleBase extends ThingBase { "startDate"?: SchemaValue; } -type RoleLeaf = Omit & { +export type RoleLeaf = Omit & { "@type": "Role"; } & { [key in TProperty]: TContent; @@ -90,7 +90,7 @@ export type Role = RoleLeaf< export type Text = string; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Role; @@ -98,7 +98,7 @@ export type Intangible = IntangibleLeaf | Role; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible; diff --git a/packages/schema-dts-gen/test/baselines/simple_test.ts b/packages/schema-dts-gen/test/baselines/simple_test.ts index 36e49d8..9d1f50a 100644 --- a/packages/schema-dts-gen/test/baselines/simple_test.ts +++ b/packages/schema-dts-gen/test/baselines/simple_test.ts @@ -35,8 +35,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -60,7 +60,7 @@ export type Text = string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/sorted_enum_test.ts b/packages/schema-dts-gen/test/baselines/sorted_enum_test.ts index 0c8db06..bee1106 100644 --- a/packages/schema-dts-gen/test/baselines/sorted_enum_test.ts +++ b/packages/schema-dts-gen/test/baselines/sorted_enum_test.ts @@ -36,8 +36,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -58,7 +58,7 @@ export type WithActionConstraints = T & InputActionConstra interface ThingBase extends Partial { } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** A Thing! */ diff --git a/packages/schema-dts-gen/test/baselines/sorted_props_test.ts b/packages/schema-dts-gen/test/baselines/sorted_props_test.ts index 380c4d3..c8981a9 100644 --- a/packages/schema-dts-gen/test/baselines/sorted_props_test.ts +++ b/packages/schema-dts-gen/test/baselines/sorted_props_test.ts @@ -44,8 +44,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -72,7 +72,7 @@ interface ThingBase extends Partial { "c"?: SchemaValue; "d"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/sorted_proptypes_test.ts b/packages/schema-dts-gen/test/baselines/sorted_proptypes_test.ts index 5a34bdf..1b69236 100644 --- a/packages/schema-dts-gen/test/baselines/sorted_proptypes_test.ts +++ b/packages/schema-dts-gen/test/baselines/sorted_proptypes_test.ts @@ -52,8 +52,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -87,7 +87,7 @@ export type Time = string; interface ThingBase extends Partial { "a"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf; diff --git a/packages/schema-dts-gen/test/baselines/stringlike_http_test.ts b/packages/schema-dts-gen/test/baselines/stringlike_http_test.ts index 1a1997e..0eaf12f 100644 --- a/packages/schema-dts-gen/test/baselines/stringlike_http_test.ts +++ b/packages/schema-dts-gen/test/baselines/stringlike_http_test.ts @@ -60,8 +60,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -80,14 +80,14 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface QuantityLeaf extends ThingBase { +export interface QuantityLeaf extends ThingBase { "@type": "Quantity"; } export type Quantity = QuantityLeaf | string; export type Text = URL | string; -interface EntryPointLeaf extends ThingBase { +export interface EntryPointLeaf extends ThingBase { "@type": "EntryPoint"; } export type EntryPoint = EntryPointLeaf | string; @@ -97,7 +97,7 @@ interface OrganizationBase extends ThingBase { "owner"?: SchemaValue; "urlTemplate"?: SchemaValue; } -interface OrganizationLeaf extends OrganizationBase { +export interface OrganizationLeaf extends OrganizationBase { "@type": "Organization"; } export type Organization = OrganizationLeaf | string; @@ -106,12 +106,12 @@ interface PersonBase extends ThingBase { "height"?: SchemaValue; "locatedIn"?: SchemaValue; } -interface PersonLeaf extends PersonBase { +export interface PersonLeaf extends PersonBase { "@type": "Person"; } export type Person = PersonLeaf | string; -interface PlaceLeaf extends ThingBase { +export interface PlaceLeaf extends ThingBase { "@type": "Place"; } export type Place = PlaceLeaf | string; @@ -119,7 +119,7 @@ export type Place = PlaceLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | EntryPoint | Organization | Person | Place | Quantity; diff --git a/packages/schema-dts-gen/test/baselines/stringlike_https_test.ts b/packages/schema-dts-gen/test/baselines/stringlike_https_test.ts index 3f775be..62af622 100644 --- a/packages/schema-dts-gen/test/baselines/stringlike_https_test.ts +++ b/packages/schema-dts-gen/test/baselines/stringlike_https_test.ts @@ -60,8 +60,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -80,14 +80,14 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface QuantityLeaf extends ThingBase { +export interface QuantityLeaf extends ThingBase { "@type": "Quantity"; } export type Quantity = QuantityLeaf | string; export type Text = URL | string; -interface EntryPointLeaf extends ThingBase { +export interface EntryPointLeaf extends ThingBase { "@type": "EntryPoint"; } export type EntryPoint = EntryPointLeaf | string; @@ -97,7 +97,7 @@ interface OrganizationBase extends ThingBase { "owner"?: SchemaValue; "urlTemplate"?: SchemaValue; } -interface OrganizationLeaf extends OrganizationBase { +export interface OrganizationLeaf extends OrganizationBase { "@type": "Organization"; } export type Organization = OrganizationLeaf | string; @@ -106,12 +106,12 @@ interface PersonBase extends ThingBase { "height"?: SchemaValue; "locatedIn"?: SchemaValue; } -interface PersonLeaf extends PersonBase { +export interface PersonLeaf extends PersonBase { "@type": "Person"; } export type Person = PersonLeaf | string; -interface PlaceLeaf extends ThingBase { +export interface PlaceLeaf extends ThingBase { "@type": "Place"; } export type Place = PlaceLeaf | string; @@ -119,7 +119,7 @@ export type Place = PlaceLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | EntryPoint | Organization | Person | Place | Quantity; diff --git a/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_test.ts b/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_test.ts index 792e4ab..0047954 100644 --- a/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_test.ts +++ b/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_test.ts @@ -49,8 +49,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -69,32 +69,32 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface EnumerationLeaf extends ThingBase { +export interface EnumerationLeaf extends ThingBase { "@type": "Enumeration"; } export type Enumeration = EnumerationLeaf | MedicalEnumeration; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Enumeration; -interface MedicalEnumerationLeaf extends ThingBase { +export interface MedicalEnumerationLeaf extends ThingBase { "@type": "MedicalEnumeration"; } export type MedicalEnumeration = MedicalEnumerationLeaf | MedicalProcedureType; -interface MedicalProcedureLeaf extends ThingBase { +export interface MedicalProcedureLeaf extends ThingBase { "@type": "MedicalProcedure"; } export type MedicalProcedure = MedicalProcedureLeaf | SurgicalProcedure; -interface MedicalProcedureTypeLeaf extends ThingBase { +export interface MedicalProcedureTypeLeaf extends ThingBase { "@type": "MedicalProcedureType"; } export type MedicalProcedureType = "http://schema.org/SurgicalProcedure" | "https://schema.org/SurgicalProcedure" | "SurgicalProcedure" | MedicalProcedureTypeLeaf; -interface SurgicalProcedureLeaf extends ThingBase { +export interface SurgicalProcedureLeaf extends ThingBase { "@type": "SurgicalProcedure"; } /** A type of medical procedure that involves invasive surgical techniques. */ @@ -102,7 +102,7 @@ export type SurgicalProcedure = SurgicalProcedureLeaf; interface ThingBase extends Partial { } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible | MedicalProcedure; diff --git a/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_v2_test.ts b/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_v2_test.ts index 861d513..c8fca8e 100644 --- a/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_v2_test.ts +++ b/packages/schema-dts-gen/test/baselines/surgical_procedure_3_4_v2_test.ts @@ -49,8 +49,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -69,32 +69,32 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface EnumerationLeaf extends ThingBase { +export interface EnumerationLeaf extends ThingBase { "@type": "Enumeration"; } export type Enumeration = EnumerationLeaf | MedicalEnumeration; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Enumeration; -interface MedicalEnumerationLeaf extends ThingBase { +export interface MedicalEnumerationLeaf extends ThingBase { "@type": "MedicalEnumeration"; } export type MedicalEnumeration = MedicalEnumerationLeaf | MedicalProcedureType; -interface MedicalProcedureLeaf extends ThingBase { +export interface MedicalProcedureLeaf extends ThingBase { "@type": "MedicalProcedure"; } export type MedicalProcedure = MedicalProcedureLeaf | SurgicalProcedure; -interface MedicalProcedureTypeLeaf extends ThingBase { +export interface MedicalProcedureTypeLeaf extends ThingBase { "@type": "MedicalProcedureType"; } export type MedicalProcedureType = "http://schema.org/SurgicalProcedure" | "https://schema.org/SurgicalProcedure" | "SurgicalProcedure" | MedicalProcedureTypeLeaf; -interface SurgicalProcedureLeaf extends ThingBase { +export interface SurgicalProcedureLeaf extends ThingBase { "@type": "SurgicalProcedure"; } /** A type of medical procedure that involves invasive surgical techniques. */ @@ -102,7 +102,7 @@ export type SurgicalProcedure = SurgicalProcedureLeaf; interface ThingBase extends Partial { } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible | MedicalProcedure; diff --git a/packages/schema-dts-gen/test/baselines/surgical_procedure_test.ts b/packages/schema-dts-gen/test/baselines/surgical_procedure_test.ts index 592fd6c..b5e6554 100644 --- a/packages/schema-dts-gen/test/baselines/surgical_procedure_test.ts +++ b/packages/schema-dts-gen/test/baselines/surgical_procedure_test.ts @@ -74,8 +74,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -94,69 +94,69 @@ type OutputActionConstraints = Partial<{ /** Provides input and output action constraints for an action. */ export type WithActionConstraints = T & InputActionConstraints & OutputActionConstraints; -interface DiagnosticProcedureLeaf extends ThingBase { +export interface DiagnosticProcedureLeaf extends ThingBase { "@type": "DiagnosticProcedure"; } export type DiagnosticProcedure = DiagnosticProcedureLeaf; -interface EnumerationLeaf extends ThingBase { +export interface EnumerationLeaf extends ThingBase { "@type": "Enumeration"; } export type Enumeration = EnumerationLeaf | MedicalEnumeration; -interface IntangibleLeaf extends ThingBase { +export interface IntangibleLeaf extends ThingBase { "@type": "Intangible"; } export type Intangible = IntangibleLeaf | Enumeration; -interface MedicalEntityLeaf extends ThingBase { +export interface MedicalEntityLeaf extends ThingBase { "@type": "MedicalEntity"; } export type MedicalEntity = MedicalEntityLeaf | MedicalProcedure; -interface MedicalEnumerationLeaf extends ThingBase { +export interface MedicalEnumerationLeaf extends ThingBase { "@type": "MedicalEnumeration"; } export type MedicalEnumeration = MedicalEnumerationLeaf | MedicalProcedureType | PhysicalExam; -interface MedicalProcedureLeaf extends ThingBase { +export interface MedicalProcedureLeaf extends ThingBase { "@type": "MedicalProcedure"; } /** A process of care used in either a diagnostic, therapeutic, preventive or palliative capacity that relies on invasive (surgical), non-invasive, or other techniques. */ export type MedicalProcedure = MedicalProcedureLeaf | DiagnosticProcedure | PalliativeProcedure | PhysicalExam | SurgicalProcedure | TherapeuticProcedure; -interface MedicalProcedureTypeLeaf extends ThingBase { +export interface MedicalProcedureTypeLeaf extends ThingBase { "@type": "MedicalProcedureType"; } /** An enumeration that describes different types of medical procedures. */ export type MedicalProcedureType = "http://schema.org/NoninvasiveProcedure" | "https://schema.org/NoninvasiveProcedure" | "NoninvasiveProcedure" | "http://schema.org/PercutaneousProcedure" | "https://schema.org/PercutaneousProcedure" | "PercutaneousProcedure" | MedicalProcedureTypeLeaf; -interface MedicalTherapyLeaf extends ThingBase { +export interface MedicalTherapyLeaf extends ThingBase { "@type": "MedicalTherapy"; } export type MedicalTherapy = MedicalTherapyLeaf | PalliativeProcedure; interface PalliativeProcedureBase extends ThingBase, ThingBase { } -interface PalliativeProcedureLeaf extends PalliativeProcedureBase { +export interface PalliativeProcedureLeaf extends PalliativeProcedureBase { "@type": "PalliativeProcedure"; } export type PalliativeProcedure = PalliativeProcedureLeaf; interface PhysicalExamBase extends ThingBase, ThingBase { } -interface PhysicalExamLeaf extends PhysicalExamBase { +export interface PhysicalExamLeaf extends PhysicalExamBase { "@type": "PhysicalExam"; } export type PhysicalExam = "http://schema.org/Head" | "https://schema.org/Head" | "Head" | "http://schema.org/Neuro" | "https://schema.org/Neuro" | "Neuro" | PhysicalExamLeaf; -interface SurgicalProcedureLeaf extends ThingBase { +export interface SurgicalProcedureLeaf extends ThingBase { "@type": "SurgicalProcedure"; } /** A medical procedure involving an incision with instruments; performed for diagnose, or therapeutic purposes. */ export type SurgicalProcedure = SurgicalProcedureLeaf; -interface TherapeuticProcedureLeaf extends ThingBase { +export interface TherapeuticProcedureLeaf extends ThingBase { "@type": "TherapeuticProcedure"; } export type TherapeuticProcedure = TherapeuticProcedureLeaf | MedicalTherapy; @@ -164,7 +164,7 @@ export type TherapeuticProcedure = TherapeuticProcedureLeaf | MedicalTherapy; interface ThingBase extends Partial { "procedureType"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } export type Thing = ThingLeaf | Intangible | MedicalEntity; diff --git a/packages/schema-dts-gen/test/baselines/transitive_class_test.ts b/packages/schema-dts-gen/test/baselines/transitive_class_test.ts index 2c938e4..fb0b2f7 100644 --- a/packages/schema-dts-gen/test/baselines/transitive_class_test.ts +++ b/packages/schema-dts-gen/test/baselines/transitive_class_test.ts @@ -39,8 +39,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; @@ -62,7 +62,7 @@ export type WithActionConstraints = T & InputActionConstra /** Data type: Text. */ export type Text = string; -interface PersonLeaf extends ThingBase { +export interface PersonLeaf extends ThingBase { "@type": "Person"; } /** ABC */ @@ -71,7 +71,7 @@ export type Person = PersonLeaf | string; interface ThingBase extends Partial { "name"?: SchemaValue; } -interface ThingLeaf extends ThingBase { +export interface ThingLeaf extends ThingBase { "@type": "Thing"; } /** ABC */ diff --git a/packages/schema-dts-gen/test/baselines/url_test.ts b/packages/schema-dts-gen/test/baselines/url_test.ts index f237301..f23a719 100644 --- a/packages/schema-dts-gen/test/baselines/url_test.ts +++ b/packages/schema-dts-gen/test/baselines/url_test.ts @@ -35,8 +35,8 @@ test(`baseline_${basename(import.meta.url)}`, async () => { ); expect(actual).toMatchInlineSnapshot(` -"import type { JsonLdObject, IdReference } from "schema-dts-lib"; -export type { JsonLdObject, IdReference }; +"import type { JsonLdObject, IdReference, MergeLeafTypes } from "schema-dts-lib"; +export type { JsonLdObject, IdReference, MergeLeafTypes }; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export type WithContext = T & { "@context": "https://schema.org"; diff --git a/packages/schema-dts-gen/test/ts/class_test.ts b/packages/schema-dts-gen/test/ts/class_test.ts index 3c1664b..b87fecb 100644 --- a/packages/schema-dts-gen/test/ts/class_test.ts +++ b/packages/schema-dts-gen/test/ts/class_test.ts @@ -71,13 +71,13 @@ describe('Class', () => { const ctx = new Context(); ctx.setUrlContext('https://schema.org/'); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonBase extends Partial { - } - interface PersonLeaf extends PersonBase { - "@type": "Person"; - } - export type Person = PersonLeaf;" - `); +"interface PersonBase extends Partial { +} +export interface PersonLeaf extends PersonBase { + "@type": "Person"; +} +export type Person = PersonLeaf;" +`); }); it('empty (with parent)', () => { @@ -86,11 +86,11 @@ describe('Class', () => { addParent(cls, 'https://schema.org/Thing'); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonLeaf extends ThingBase { - "@type": "Person"; - } - export type Person = PersonLeaf;" - `); +"export interface PersonLeaf extends ThingBase { + "@type": "Person"; +} +export type Person = PersonLeaf;" +`); }); it('empty (two parents)', () => { @@ -100,13 +100,13 @@ describe('Class', () => { addParent(cls, 'https://schema.org/Thing2'); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonBase extends Thing1Base, Thing2Base { - } - interface PersonLeaf extends PersonBase { - "@type": "Person"; - } - export type Person = PersonLeaf;" - `); +"interface PersonBase extends Thing1Base, Thing2Base { +} +export interface PersonLeaf extends PersonBase { + "@type": "Person"; +} +export type Person = PersonLeaf;" +`); }); it('deprecated once (only)', () => { @@ -126,12 +126,12 @@ describe('Class', () => { ).toBe(true); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonLeaf extends ThingBase { - "@type": "Person"; - } - /** @deprecated Use CoolPerson instead. */ - export type Person = PersonLeaf;" - `); +"export interface PersonLeaf extends ThingBase { + "@type": "Person"; +} +/** @deprecated Use CoolPerson instead. */ +export type Person = PersonLeaf;" +`); }); it('deprecated twice (alphabetical)', () => { @@ -168,12 +168,12 @@ describe('Class', () => { ).toBe(true); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonLeaf extends ThingBase { - "@type": "Person"; - } - /** @deprecated Use APerson or CoolPerson instead. */ - export type Person = PersonLeaf;" - `); +"export interface PersonLeaf extends ThingBase { + "@type": "Person"; +} +/** @deprecated Use APerson or CoolPerson instead. */ +export type Person = PersonLeaf;" +`); }); it('deprecated with comment', () => { @@ -199,16 +199,16 @@ describe('Class', () => { ).toBe(true); expect(asString(cls, ctx)).toMatchInlineSnapshot(` - "interface PersonLeaf extends ThingBase { - "@type": "Person"; - } - /** - * Fantastic - * - * @deprecated Use CoolPerson instead. - */ - export type Person = PersonLeaf;" - `); +"export interface PersonLeaf extends ThingBase { + "@type": "Person"; +} +/** + * Fantastic + * + * @deprecated Use CoolPerson instead. + */ +export type Person = PersonLeaf;" +`); }); it('complains about bad comment markup', () => { @@ -261,7 +261,7 @@ describe('Class', () => { "schema:c"?: SchemaValue; "https://abc.com/e"?: SchemaValue; } -interface schema_ALeaf extends schema_ABase { +export interface schema_ALeaf extends schema_ABase { "@type": "schema:A"; } export type schema_A = schema_ALeaf;" diff --git a/packages/schema-dts-lib/index.ts b/packages/schema-dts-lib/index.ts index 4e49009..91f80f6 100644 --- a/packages/schema-dts-lib/index.ts +++ b/packages/schema-dts-lib/index.ts @@ -12,3 +12,38 @@ export interface IdReference { /** IRI identifying the canonical address of this object. */ readonly '@id': string; } + +interface LeafLike { + '@type': string; +} + +type LeafTypesError = 'Error: Leaf types expected.' & {got: T}; + +type UnionToIntersection = ( + T extends unknown ? (value: T) => void : never +) extends (value: infer I) => void + ? I + : never; + +type CheckLeaf = + UnionToIntersection extends never ? LeafTypesError : T; + +type OmitTypeProperty = T extends unknown + ? Omit + : never; + +type MergeLeafTypesChecked< + T extends readonly [LeafLike, ...LeafLike[]], + TChecked extends readonly unknown[] = {[K in keyof T]: CheckLeaf}, +> = TChecked extends readonly [LeafLike, ...LeafLike[]] + ? UnionToIntersection> & { + '@type': {[K in keyof T]: T[K] extends {'@type': infer U} ? U : never}; + } + : LeafTypesError; + +/** + * Merges a tuple of concrete leaf types into a single schema type with a + * tuple-valued `@type`. + */ +export type MergeLeafTypes = + MergeLeafTypesChecked; diff --git a/packages/schema-dts/README.md b/packages/schema-dts/README.md index 2c58ce3..a19736c 100644 --- a/packages/schema-dts/README.md +++ b/packages/schema-dts/README.md @@ -69,6 +69,36 @@ export const MY_ORG = JsonLd({ }); ``` +### Merging Multiple Concrete Types + +If a JSON-LD object needs multiple concrete schema types, use `MergeLeafTypes` +with exported leaf types: + +```ts +import type { + MergeLeafTypes, + ProductLeaf, + SoftwareApplicationLeaf, + WithContext, +} from 'schema-dts'; + +const app: WithContext> = + { + '@context': 'https://schema.org', + '@type': ['Product', 'SoftwareApplication'], + name: 'My App', + offers: { + '@type': 'Offer', + price: 89, + priceCurrency: 'USD', + }, + operatingSystem: 'Any', + }; +``` + +`MergeLeafTypes` is intended for concrete leaf types like `ProductLeaf`, not for +union aliases like `Product`. + ### Graphs and IDs JSON-LD supports `'@graph'` objects that have richer interconnected links diff --git a/packages/schema-dts/test/mergeleaftypes.ts b/packages/schema-dts/test/mergeleaftypes.ts new file mode 100644 index 0000000..206913d --- /dev/null +++ b/packages/schema-dts/test/mergeleaftypes.ts @@ -0,0 +1,53 @@ +import { + MergeLeafTypes, + Product, + ProductLeaf, + SoftwareApplicationLeaf, + WithContext, +} from '../dist/schema'; + +const _1: WithContext> = + { + '@context': 'https://schema.org', + '@type': ['Product', 'SoftwareApplication'], + name: 'My App', + offers: { + '@type': 'Offer', + price: 89, + priceCurrency: 'USD', + }, + operatingSystem: 'Any', + }; + +const _2: WithContext> = { + '@context': 'https://schema.org', + '@type': ['Product'], + name: 'Single Product', +}; + +const _3: MergeLeafTypes<[ProductLeaf, SoftwareApplicationLeaf]>['@type'] = [ + 'Product', + 'SoftwareApplication', +]; + +const _4: MergeLeafTypes<[ProductLeaf, SoftwareApplicationLeaf]>['@type'] = [ + // @ts-expect-error MergeLeafTypes preserves tuple ordering. + 'SoftwareApplication', + // @ts-expect-error MergeLeafTypes preserves tuple ordering. + 'Product', +]; + +const _5: WithContext> = + { + '@context': 'https://schema.org', + '@type': ['Product', 'SoftwareApplication'], + name: 'My App', + // @ts-expect-error Invalid property + invalidProp: 'xyz', + }; + +// @ts-expect-error MergeLeafTypes expects concrete leaf types, not unions. +const _6: WithContext> = { + '@context': 'https://schema.org', + '@type': ['Product', 'SoftwareApplication'], +};