Skip to content

Commit 4216cea

Browse files
authored
Merge pull request #10 from cyruscollier/main
feat: Event Schema.org node
2 parents f4855de + 3891c14 commit 4216cea

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed

packages/schema-org/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './useSchemaOrg'
22
export * from './nodes/Article'
33
export * from './nodes/Breadcrumb'
44
export * from './nodes/Comment'
5+
export * from './nodes/Event'
56
export * from './nodes/HowTo'
67
export * from './nodes/Organization'
78
export * from './nodes/Person'

packages/schema-org/meta.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const RootSchemas = [
22
'Article',
33
'Breadcrumb',
44
'Comment',
5+
'Event',
56
'HowTo',
67
'Image',
78
'LocalBusiness',
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { expect } from 'vitest'
2+
import { useSetup } from '../../../.test'
3+
import { injectSchemaOrg, useSchemaOrg } from '../../useSchemaOrg'
4+
import { defineEvent } from './index'
5+
6+
describe('defineEvent', () => {
7+
it('can be registered', () => {
8+
useSetup(() => {
9+
useSchemaOrg([
10+
defineEvent({
11+
'@type': 'Event',
12+
'name': 'test',
13+
}),
14+
])
15+
16+
const { graphNodes } = injectSchemaOrg()
17+
18+
expect(graphNodes).toMatchInlineSnapshot(`
19+
[
20+
{
21+
"@id": "https://example.com/#identity",
22+
"@type": "Event",
23+
"name": "test",
24+
"url": "https://example.com/",
25+
},
26+
]
27+
`)
28+
})
29+
})
30+
})
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import type { DeepPartial } from 'utility-types'
2+
import type { Id, ResolvableDate, SchemaNodeInput, Thing } from '../../types'
3+
import {
4+
IdentityId,
5+
defineSchemaResolver,
6+
prefixId,
7+
resolveId,
8+
} from '../../utils'
9+
import type { Organization } from '../Organization'
10+
import type { PostalAddress } from '../PostalAddress'
11+
import { defineSchemaOrgComponent } from '../../components/defineSchemaOrgComponent'
12+
import type { Person } from '../Person'
13+
import type { Offer } from '../Offer'
14+
import type { ImageInput } from '../Image'
15+
16+
export interface Place extends Thing {
17+
'@type': 'Place'
18+
name: string
19+
address: PostalAddress
20+
}
21+
22+
export interface VirtualLocation extends Thing {
23+
'@type': 'VirtualLocation'
24+
/**
25+
* URL of the item.
26+
*/
27+
url: string
28+
}
29+
30+
export interface Event extends Thing {
31+
/**
32+
* Description of the event.
33+
* Describe all details of the event to make it easier for users to understand and attend the event.
34+
*/
35+
description?: string
36+
/**
37+
* The end date and time of the item (in ISO 8601 date format).
38+
*/
39+
endDate?: ResolvableDate
40+
/**
41+
* The eventAttendanceMode of an event indicates whether it occurs online, offline, or a mix.
42+
*/
43+
eventAttendanceMode?: Id
44+
/**
45+
* An eventStatus of an event represents its status; particularly useful when an event is cancelled or rescheduled.
46+
*/
47+
eventStatus?: 'EventCancelled' | 'EventMovedOnline' | 'EventPostponed' | 'EventRescheduled' | 'EventScheduled'
48+
/**
49+
* Repeated ImageObject or URL
50+
*
51+
* URL of an image or logo for the event or tour.
52+
* Including an image helps users understand and engage with your event.
53+
* We recommend that images are 1920px wide (the minimum width is 720px).
54+
*/
55+
image?: ImageInput
56+
/**
57+
* The location of the event.
58+
* There are different requirements depending on if the event is happening online or at a physical location
59+
*/
60+
location?: Place | VirtualLocation
61+
/**
62+
* An offer to provide this item—for example, an offer to sell a product,
63+
* rent the DVD of a movie, perform a service, or give away tickets to an event.
64+
* Use businessFunction to indicate the kind of transaction offered, i.e. sell, lease, etc.
65+
* This property can also be used to describe a Demand.
66+
* While this property is listed as expected on a number of common types, it can be used in others.
67+
* In that case, using a second type, such as Product or a subtype of Product, can clarify the nature of the offer.
68+
*/
69+
offers?: Offer
70+
/**
71+
* An organizer of an Event.
72+
*/
73+
organizer?: Organization | Person
74+
/**
75+
* A performer at the event—for example, a presenter, musician, musical group or actor.
76+
*/
77+
performer?: Organization | Person
78+
/**
79+
* Used in conjunction with eventStatus for rescheduled or cancelled events.
80+
* This property contains the previously scheduled start date.
81+
* For rescheduled events, the startDate property should be used for the newly scheduled start date.
82+
* In the (rare) case of an event that has been postponed and rescheduled multiple times, this field may be repeated.
83+
*/
84+
previousStartDate?: ResolvableDate
85+
/**
86+
* The start date and time of the item (in ISO 8601 date format).
87+
*/
88+
startDate?: ResolvableDate
89+
}
90+
91+
export const defineEventPartial = <K>(input?: DeepPartial<Event> & K) =>
92+
// hacky way for users to get around strict typing when using custom schema, route meta or augmentation
93+
defineEvent(input as Event)
94+
95+
/**
96+
* An event happening at a certain time and location, such as a concert, lecture, or festival.
97+
*
98+
* Ticketing information may be added via the "offers" property.
99+
* Repeated events may be structured as separate Event objects.
100+
*/
101+
export function defineEvent<T extends SchemaNodeInput<Event>>(input: T) {
102+
return defineSchemaResolver<T, Event>(input, {
103+
required: [
104+
'location',
105+
'startDate',
106+
],
107+
defaults({ canonicalHost }) {
108+
return {
109+
'@type': 'Event',
110+
'@id': prefixId(canonicalHost, IdentityId),
111+
'url': canonicalHost,
112+
}
113+
},
114+
resolve(node, client) {
115+
resolveId(node, client.canonicalHost)
116+
return node
117+
},
118+
})
119+
}
120+
121+
export const SchemaOrgEvent = defineSchemaOrgComponent('SchemaOrgEvent', defineEvent)

0 commit comments

Comments
 (0)