@escape-game-over/atlas 0.1.114 → 0.1.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/NOT-BUILT.md +2 -2
- package/package.json +1 -1
- package/src/analytics/storage.ts +34 -39
- package/src/astro/images.ts +12 -26
- package/src/astro/index.ts +2 -9
- package/src/astro/public-files.ts +11 -52
- package/src/astro/site-routes.ts +11 -55
- package/src/config.ts +8 -17
- package/src/content/rich.ts +15 -18
- package/src/i18n/catalog.ts +20 -1
- package/src/i18n/define.ts +0 -5
- package/src/i18n/translate.ts +9 -48
- package/src/index.ts +23 -160
- package/src/jsonld/article.ts +7 -17
- package/src/jsonld/business.ts +27 -28
- package/src/jsonld/creative-work.ts +8 -20
- package/src/jsonld/node.ts +37 -7
- package/src/jsonld/organization.ts +21 -30
- package/src/jsonld/place.ts +2 -6
- package/src/jsonld/product.ts +16 -22
- package/src/jsonld/service.ts +21 -37
- package/src/jsonld/video.ts +4 -8
- package/src/jsonld/website.ts +3 -5
- package/src/meta/content.ts +14 -66
- package/src/meta/index.ts +10 -32
- package/src/project.ts +4 -18
- package/src/routes/define.ts +0 -13
- package/src/site/api.ts +10 -21
- package/src/site/create.ts +18 -26
- package/src/site/page.ts +1 -10
package/src/i18n/translate.ts
CHANGED
|
@@ -78,13 +78,7 @@ export type MergedCatalog<L extends string> = Readonly<
|
|
|
78
78
|
Record<string, Readonly<Record<L, string>>>
|
|
79
79
|
>;
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
export type RawTranslate = (
|
|
83
|
-
key: string,
|
|
84
|
-
params?: Readonly<Record<string, string>>
|
|
85
|
-
) => string;
|
|
86
|
-
|
|
87
|
-
export interface RawTranslateOptions<L extends string> {
|
|
81
|
+
export interface TranslateOptions<L extends string> {
|
|
88
82
|
readonly catalog: MergedCatalog<L>;
|
|
89
83
|
readonly locale: L;
|
|
90
84
|
/**
|
|
@@ -120,7 +114,11 @@ export function lookupTemplate<L extends string>(
|
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
/**
|
|
123
|
-
* Builds
|
|
117
|
+
* Builds `t()`.
|
|
118
|
+
*
|
|
119
|
+
* Untyped: `site.translate` declares the key-aware `TranslateFor` as what it
|
|
120
|
+
* returns, and this function fits that type with no cast. The key and params
|
|
121
|
+
* checks live in the type; what fails at runtime fails here.
|
|
124
122
|
*
|
|
125
123
|
* Every failure here is a build-time failure by design: a static site should not
|
|
126
124
|
* ship a page with a literal `{name}` in the markup, so a missing message or an
|
|
@@ -132,9 +130,9 @@ export function lookupTemplate<L extends string>(
|
|
|
132
130
|
* failure wearing different brackets. `rich()` reads those, and `plain()` gives
|
|
133
131
|
* back the sentence without them.
|
|
134
132
|
*/
|
|
135
|
-
export function
|
|
136
|
-
options:
|
|
137
|
-
):
|
|
133
|
+
export function createTranslate<L extends string>(
|
|
134
|
+
options: TranslateOptions<L>
|
|
135
|
+
): (key: string, params?: Readonly<Record<string, string>>) => string {
|
|
138
136
|
const { catalog, locale, values } = options;
|
|
139
137
|
|
|
140
138
|
return (key, params) => {
|
|
@@ -211,40 +209,3 @@ export type TranslateFor<Catalog, Bound extends string = never> = <
|
|
|
211
209
|
>(
|
|
212
210
|
...args: TranslateArgsOf<Catalog, K, Bound>
|
|
213
211
|
) => string;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Builds the typed `t()` factory for one catalog type.
|
|
217
|
-
*
|
|
218
|
-
* Curried for the usual reason — `Catalog` must be supplied explicitly while the
|
|
219
|
-
* locale stays inferred, and TypeScript has no partial type-argument inference.
|
|
220
|
-
* `Catalog` is the *base* catalog's type (it carries the literal strings the
|
|
221
|
-
* placeholders are read from); the value passed in is the merged runtime
|
|
222
|
-
* catalog, which only needs to be indexable by key and locale.
|
|
223
|
-
*/
|
|
224
|
-
export function createTranslateFactory<Catalog, L extends string>() {
|
|
225
|
-
return function createTranslate<Bound extends string = never>(
|
|
226
|
-
catalog: MergedCatalog<L>,
|
|
227
|
-
locale: L,
|
|
228
|
-
values?: Readonly<Record<Bound, string>>
|
|
229
|
-
): TranslateFor<Catalog, Bound> {
|
|
230
|
-
const raw = createRawTranslate({
|
|
231
|
-
catalog,
|
|
232
|
-
locale,
|
|
233
|
-
...(values === undefined ? {} : { values }),
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
function t<K extends StringKeys<Catalog>>(
|
|
237
|
-
...args: TranslateArgsOf<Catalog, K, Bound>
|
|
238
|
-
): string {
|
|
239
|
-
// The conditional tuple cannot be destructured directly; the runtime
|
|
240
|
-
// shape is always `[key]` or `[key, params]`.
|
|
241
|
-
const [key, params] = args as [
|
|
242
|
-
K,
|
|
243
|
-
Readonly<Record<string, string>>?,
|
|
244
|
-
];
|
|
245
|
-
return raw(key, params);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return t;
|
|
249
|
-
};
|
|
250
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -18,19 +18,14 @@ export {
|
|
|
18
18
|
CONSENT_CATEGORIES,
|
|
19
19
|
CONSENT_MONTHS,
|
|
20
20
|
type ConsentCategory,
|
|
21
|
-
type ConsentChoice,
|
|
22
|
-
type ConsentChoices,
|
|
23
21
|
} from "./analytics/consent-storage.ts";
|
|
24
22
|
export {
|
|
25
23
|
type AnalyticsSettings,
|
|
26
|
-
type AnalyticsTags,
|
|
27
24
|
type AxonPixelSettings,
|
|
28
25
|
type ClaritySettings,
|
|
29
|
-
CONSENT_UPDATE_GLOBAL,
|
|
30
26
|
type ConsentDefaults,
|
|
31
27
|
type ConsentState,
|
|
32
28
|
consentRequired,
|
|
33
|
-
consentVendors,
|
|
34
29
|
type DripSettings,
|
|
35
30
|
type GoogleSettings,
|
|
36
31
|
type GoogleTagId,
|
|
@@ -45,74 +40,36 @@ export {
|
|
|
45
40
|
type Uuid,
|
|
46
41
|
} from "./analytics/index.ts";
|
|
47
42
|
export {
|
|
48
|
-
type AtlasStoredId,
|
|
49
|
-
compareStoredItems,
|
|
50
|
-
type Lifetime,
|
|
51
43
|
STORAGE_VENDOR_NAMES,
|
|
52
|
-
type StorageVendor,
|
|
53
44
|
type StoredId,
|
|
54
45
|
type StoredItem,
|
|
55
46
|
type StoredItemsOptions,
|
|
56
47
|
storedItems,
|
|
57
|
-
withPurposes,
|
|
58
48
|
} from "./analytics/storage.ts";
|
|
59
|
-
export {
|
|
60
|
-
checkEscapeNavigator,
|
|
61
|
-
ESCAPE_NAVIGATOR_LOADER,
|
|
62
|
-
type EscapeNavigatorVars,
|
|
63
|
-
type EscapeNavigatorWidget,
|
|
64
|
-
escapeNavigatorLanguage,
|
|
65
|
-
} from "./booking/escape-navigator.ts";
|
|
66
|
-
export {
|
|
67
|
-
checkEscapeAll,
|
|
68
|
-
ESCAPEALL_LANGUAGES,
|
|
69
|
-
type EscapeAllLanguage,
|
|
70
|
-
type EscapeAllVars,
|
|
71
|
-
type EscapeAllWidget,
|
|
72
|
-
escapeAllAssets,
|
|
73
|
-
escapeAllLanguage,
|
|
74
|
-
} from "./booking/escapeall.ts";
|
|
75
|
-
export {
|
|
76
|
-
checkFourEscape,
|
|
77
|
-
FOUR_ESCAPE_LANGUAGES,
|
|
78
|
-
FOUR_ESCAPE_SCRIPT,
|
|
79
|
-
FOUR_ESCAPE_STYLESHEET,
|
|
80
|
-
type FourEscapeLanguage,
|
|
81
|
-
type FourEscapeVars,
|
|
82
|
-
type FourEscapeWidget,
|
|
83
|
-
fourEscapeLanguage,
|
|
84
|
-
fourEscapeSettings,
|
|
85
|
-
fourEscapeStyle,
|
|
86
|
-
} from "./booking/four-escape.ts";
|
|
49
|
+
export type { EscapeNavigatorWidget } from "./booking/escape-navigator.ts";
|
|
87
50
|
export type {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
BookingWidgetVars,
|
|
92
|
-
} from "./booking/widget.ts";
|
|
51
|
+
EscapeAllLanguage,
|
|
52
|
+
EscapeAllWidget,
|
|
53
|
+
} from "./booking/escapeall.ts";
|
|
93
54
|
export type {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
} from "./config.ts";
|
|
55
|
+
FourEscapeLanguage,
|
|
56
|
+
FourEscapeVars,
|
|
57
|
+
FourEscapeWidget,
|
|
58
|
+
} from "./booking/four-escape.ts";
|
|
59
|
+
export type { BookingVendor, BookingWidget } from "./booking/widget.ts";
|
|
60
|
+
export type { LanguageTag, LocaleMeta, LocalesOf } from "./config.ts";
|
|
101
61
|
export {
|
|
102
62
|
type AddressFormatOptions,
|
|
103
63
|
type AddressLineOptions,
|
|
104
64
|
addressLine,
|
|
105
65
|
addressLines,
|
|
106
|
-
assertCoordinates,
|
|
107
66
|
type CallingCode,
|
|
108
67
|
type Coordinates,
|
|
109
68
|
type CountryCode,
|
|
110
69
|
type E164,
|
|
111
70
|
type EmailAddress,
|
|
112
71
|
e164,
|
|
113
|
-
e164Of,
|
|
114
72
|
formatPhone,
|
|
115
|
-
isEmailAddress,
|
|
116
73
|
type MailtoUrl,
|
|
117
74
|
mailtoHref,
|
|
118
75
|
type PhoneNumber,
|
|
@@ -132,44 +89,26 @@ export {
|
|
|
132
89
|
// them has a second `rich()` that is not bound to the site's route table — so
|
|
133
90
|
// a slot filled with a route id resolves against nothing there. `site.rich(locale)` is
|
|
134
91
|
// the only way in, and `Span` is what a renderer switches on.
|
|
135
|
-
export {
|
|
136
|
-
|
|
137
|
-
type LinkTarget,
|
|
138
|
-
type MessageBindings,
|
|
139
|
-
type PlainTextFor,
|
|
140
|
-
plain,
|
|
141
|
-
type RichText,
|
|
142
|
-
type RichTextFor,
|
|
143
|
-
type Span,
|
|
144
|
-
} from "./content/index.ts";
|
|
145
|
-
export {
|
|
146
|
-
COUNTRY_CODES,
|
|
147
|
-
countriesFor,
|
|
148
|
-
type NamedCountry,
|
|
149
|
-
} from "./countries.ts";
|
|
92
|
+
export { html, plain, type RichText, type Span } from "./content/index.ts";
|
|
93
|
+
export { countriesFor, type NamedCountry } from "./countries.ts";
|
|
150
94
|
// `quantitiesOf`, `quantityRange` and `isContiguous` are deliberately not here.
|
|
151
95
|
// They are how lib decides between "2–6" and "2, 4, 6", and a consumer holding
|
|
152
96
|
// them writes that decision a second time — which is how `llms.txt` came to
|
|
153
97
|
// advertise a range for a room that skips sizes. `formatQuantities` answers it
|
|
154
98
|
// for prose and `quantitiesFor` for structured data; both read the same tiers.
|
|
155
99
|
export type { CurrencyCode } from "./currency.ts";
|
|
156
|
-
export type { GeneratedFile } from "./file.ts";
|
|
157
100
|
export type { PublicFilePath, PublicFileRegistry } from "./files.ts";
|
|
158
101
|
export type { Font, Fonts } from "./fonts.ts";
|
|
159
102
|
export {
|
|
160
|
-
assertHours,
|
|
161
103
|
type DayHours,
|
|
162
104
|
type FormattedHours,
|
|
163
105
|
formatHours,
|
|
164
|
-
formatTime,
|
|
165
|
-
groupHours,
|
|
166
106
|
type HourCycle,
|
|
167
107
|
type HoursFormat,
|
|
168
108
|
type HoursGroup,
|
|
169
109
|
type HoursSentenceFormat,
|
|
170
110
|
hoursSentence,
|
|
171
111
|
type OpenStatus,
|
|
172
|
-
openStatus,
|
|
173
112
|
type TimeFormat,
|
|
174
113
|
type TimeOfDay,
|
|
175
114
|
type TimeRange,
|
|
@@ -177,42 +116,18 @@ export {
|
|
|
177
116
|
type Weekday,
|
|
178
117
|
type WeeklyHours,
|
|
179
118
|
} from "./hours.ts";
|
|
180
|
-
export type {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
ProjectCatalog,
|
|
184
|
-
PublishedOf,
|
|
185
|
-
} from "./i18n/catalog.ts";
|
|
186
|
-
export type {
|
|
187
|
-
BaseCatalog,
|
|
188
|
-
CatalogCovers,
|
|
189
|
-
MessageOverrides,
|
|
190
|
-
OverrideCatalog,
|
|
191
|
-
} from "./i18n/define.ts";
|
|
192
|
-
export type {
|
|
193
|
-
EntryPlaceholders,
|
|
194
|
-
Placeholders,
|
|
195
|
-
} from "./i18n/placeholders.ts";
|
|
196
|
-
export type {
|
|
197
|
-
MessageParamsOf,
|
|
198
|
-
TranslateArgsOf,
|
|
199
|
-
TranslateFor,
|
|
200
|
-
} from "./i18n/translate.ts";
|
|
119
|
+
export type { CatalogKey } from "./i18n/catalog.ts";
|
|
120
|
+
export type { CatalogCovers, MessageOverrides } from "./i18n/define.ts";
|
|
121
|
+
export type { MessageParamsOf } from "./i18n/translate.ts";
|
|
201
122
|
export type { ImageAsset } from "./image.ts";
|
|
202
123
|
export {
|
|
203
|
-
type ArticleInput,
|
|
204
|
-
article,
|
|
205
|
-
type BreadcrumbStep,
|
|
206
124
|
type BusinessId,
|
|
207
|
-
breadcrumbList,
|
|
208
125
|
businessId,
|
|
209
|
-
type CatalogEntry,
|
|
210
126
|
type CreativeWorkInput,
|
|
211
127
|
type CreativeWorkProperty,
|
|
212
128
|
creativeWork,
|
|
213
129
|
type FaqEntry,
|
|
214
130
|
faqPage,
|
|
215
|
-
geoCoordinates,
|
|
216
131
|
type JsonLdNode,
|
|
217
132
|
type LocalBusinessInput,
|
|
218
133
|
localBusiness,
|
|
@@ -220,45 +135,30 @@ export {
|
|
|
220
135
|
type OrganizationId,
|
|
221
136
|
type OrganizationInput,
|
|
222
137
|
offerCatalog,
|
|
223
|
-
openingHours,
|
|
224
138
|
organization,
|
|
225
139
|
organizationId,
|
|
226
140
|
type ProductInput,
|
|
227
|
-
postalAddress,
|
|
228
141
|
product,
|
|
229
142
|
quantitativeValue,
|
|
230
143
|
quantitiesFor,
|
|
231
144
|
type ServiceArea,
|
|
232
145
|
type ServiceId,
|
|
233
146
|
type ServiceInput,
|
|
234
|
-
serializeJsonLd,
|
|
235
147
|
service,
|
|
236
|
-
serviceId,
|
|
237
148
|
type VideoInput,
|
|
238
149
|
type VideoSource,
|
|
239
150
|
videoObject,
|
|
240
151
|
type WebsiteId,
|
|
241
152
|
type WebsiteInput,
|
|
242
153
|
website,
|
|
243
|
-
websiteId,
|
|
244
154
|
} from "./jsonld/index.ts";
|
|
245
|
-
export {
|
|
246
|
-
buildLlms,
|
|
247
|
-
type LlmsConfig,
|
|
248
|
-
type LlmsItem,
|
|
249
|
-
type LlmsSection,
|
|
250
|
-
} from "./llms.ts";
|
|
155
|
+
export type { LlmsSection } from "./llms.ts";
|
|
251
156
|
export { googleMapsUrl, type MapPlace, type MapsTarget } from "./map.ts";
|
|
252
157
|
export {
|
|
253
158
|
type ArticleContent,
|
|
254
|
-
buildMeta,
|
|
255
|
-
buildNotFoundMeta,
|
|
256
159
|
fitDescription,
|
|
257
160
|
fitTitle,
|
|
258
161
|
type MetaContent,
|
|
259
|
-
type MetaTag,
|
|
260
|
-
type OpenGraphType,
|
|
261
|
-
type PageKind,
|
|
262
162
|
type RobotsPolicy,
|
|
263
163
|
type ShareImage,
|
|
264
164
|
type SiteVerification,
|
|
@@ -267,8 +167,6 @@ export {
|
|
|
267
167
|
type AudiencePrice,
|
|
268
168
|
type AudienceTier,
|
|
269
169
|
amountAt,
|
|
270
|
-
assertAudiences,
|
|
271
|
-
assertPriceTiers,
|
|
272
170
|
formatQuantities,
|
|
273
171
|
type Price,
|
|
274
172
|
type PriceTier,
|
|
@@ -284,70 +182,35 @@ export {
|
|
|
284
182
|
type PriceFormat,
|
|
285
183
|
} from "./price-format.ts";
|
|
286
184
|
export type {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
buildCloudflareRedirects,
|
|
293
|
-
buildRedirects,
|
|
294
|
-
type CloudflareRedirectsOptions,
|
|
295
|
-
type ExternalUrl,
|
|
296
|
-
type ProjectRedirects,
|
|
297
|
-
type RedirectKind,
|
|
298
|
-
type RedirectRule,
|
|
299
|
-
type RedirectStatus,
|
|
300
|
-
type RedirectTarget,
|
|
301
|
-
type ResolvedRedirect,
|
|
302
|
-
type SitePath,
|
|
303
|
-
type ValidateRedirectTargets,
|
|
185
|
+
ProjectRedirects,
|
|
186
|
+
RedirectKind,
|
|
187
|
+
RedirectRule,
|
|
188
|
+
RedirectTarget,
|
|
189
|
+
SitePath,
|
|
304
190
|
} from "./redirects.ts";
|
|
305
|
-
export type { RobotsConfig, RobotsGroup } from "./robots.ts";
|
|
306
|
-
export type {
|
|
307
|
-
ChangeFreq,
|
|
308
|
-
EnabledRouteIdFor,
|
|
309
|
-
RouteData,
|
|
310
|
-
RouteOverride,
|
|
311
|
-
RouteOverrides,
|
|
312
|
-
RouteRegistry,
|
|
313
|
-
RouteSitemap,
|
|
314
|
-
} from "./routes/define.ts";
|
|
315
191
|
export {
|
|
316
192
|
enableRoutes,
|
|
317
|
-
type FamilyMember,
|
|
318
|
-
type FamilyMemberInput,
|
|
319
|
-
type FamilyMemberSlugs,
|
|
320
|
-
type FamilyOptions,
|
|
321
193
|
familyGuard,
|
|
322
194
|
familyMemberSlugs,
|
|
323
195
|
type RouteIdsOf,
|
|
324
196
|
} from "./routes/family.ts";
|
|
325
|
-
export type { RouteEntry } from "./routes/resolve.ts";
|
|
326
197
|
export { defineSite } from "./site/define.ts";
|
|
327
198
|
export type {
|
|
328
|
-
Alternate,
|
|
329
199
|
Crumb,
|
|
330
200
|
LinkOptions,
|
|
331
201
|
LlmsOptions,
|
|
332
|
-
LocaleLink,
|
|
333
202
|
PageContent,
|
|
334
203
|
PageMeta,
|
|
335
204
|
PageProps,
|
|
336
205
|
PerRoute,
|
|
337
|
-
Site,
|
|
338
|
-
StaticPath,
|
|
339
206
|
} from "./site/index.ts";
|
|
340
|
-
export type {
|
|
341
|
-
export {
|
|
342
|
-
export type { IsoDate, Letter, NonEmpty, StringKeys } from "./types.ts";
|
|
207
|
+
export type { TimeZone } from "./time-zones.ts";
|
|
208
|
+
export type { IsoDate, NonEmpty, StringKeys } from "./types.ts";
|
|
343
209
|
export {
|
|
344
210
|
absoluteUrl,
|
|
345
|
-
type Hash,
|
|
346
211
|
type HttpsUrl,
|
|
347
|
-
isHash,
|
|
348
212
|
isHttpsUrl,
|
|
349
213
|
isUrlPath,
|
|
350
214
|
joinUrl,
|
|
351
|
-
normalizeOrigin,
|
|
352
215
|
type UrlPath,
|
|
353
216
|
} from "./url.ts";
|
package/src/jsonld/article.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { IsoDate } from "../types.ts";
|
|
|
2
2
|
import type { HttpsUrl } from "../url.ts";
|
|
3
3
|
import { warn } from "../warn.ts";
|
|
4
4
|
import type { BusinessId, OrganizationId } from "./ids.ts";
|
|
5
|
-
import { type JsonLdNode, oneOrMany } from "./node.ts";
|
|
5
|
+
import { type JsonLdNode, listed, oneOrMany, reference } from "./node.ts";
|
|
6
6
|
|
|
7
7
|
export interface ArticleInput {
|
|
8
8
|
/**
|
|
@@ -137,29 +137,19 @@ export function article(item: ArticleInput): JsonLdNode {
|
|
|
137
137
|
return {
|
|
138
138
|
"@type": item.kind ?? "Article",
|
|
139
139
|
headline: item.headline,
|
|
140
|
-
|
|
141
|
-
? {}
|
|
142
|
-
: { description: item.description }),
|
|
140
|
+
description: item.description,
|
|
143
141
|
// Not `url`: an article is a thing, and this is the page it is *on*.
|
|
144
142
|
mainEntityOfPage: item.url,
|
|
145
143
|
datePublished: item.datePublished,
|
|
146
|
-
|
|
147
|
-
? {}
|
|
148
|
-
: { dateModified: item.dateModified }),
|
|
144
|
+
dateModified: item.dateModified,
|
|
149
145
|
// Passed through in the shape it arrived in, bar a list of one — which
|
|
150
146
|
// is `schemaType`'s rule applied to a second field: writing `[x]` is
|
|
151
147
|
// fine, emitting it reads as a bug.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
: { author: { "@id": item.author } }),
|
|
156
|
-
...(item.publisher === undefined
|
|
157
|
-
? {}
|
|
158
|
-
: { publisher: { "@id": item.publisher } }),
|
|
148
|
+
image: item.image === undefined ? undefined : oneOrMany(item.image),
|
|
149
|
+
author: reference(item.author),
|
|
150
|
+
publisher: reference(item.publisher),
|
|
159
151
|
// An empty list is not a set of no keywords, it is a field saying
|
|
160
152
|
// nothing — so it is left out, as every optional here is.
|
|
161
|
-
|
|
162
|
-
? {}
|
|
163
|
-
: { keywords: item.tags }),
|
|
153
|
+
keywords: listed(item.tags),
|
|
164
154
|
};
|
|
165
155
|
}
|
package/src/jsonld/business.ts
CHANGED
|
@@ -10,7 +10,13 @@ import type { ImageAsset } from "../image.ts";
|
|
|
10
10
|
import type { NonEmpty } from "../types.ts";
|
|
11
11
|
import { absoluteUrl, type HttpsUrl } from "../url.ts";
|
|
12
12
|
import { businessId, type OrganizationId } from "./ids.ts";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
alternateName,
|
|
15
|
+
type JsonLdNode,
|
|
16
|
+
listed,
|
|
17
|
+
reference,
|
|
18
|
+
schemaType,
|
|
19
|
+
} from "./node.ts";
|
|
14
20
|
import { geoCoordinates, openingHours, postalAddress } from "./place.ts";
|
|
15
21
|
|
|
16
22
|
export interface LocalBusinessInput {
|
|
@@ -173,34 +179,27 @@ export function localBusiness(business: LocalBusinessInput): JsonLdNode {
|
|
|
173
179
|
"@type": schemaType(business.type ?? "LocalBusiness"),
|
|
174
180
|
"@id": businessId(business.url, business.location),
|
|
175
181
|
name: business.name,
|
|
176
|
-
|
|
182
|
+
alternateName: alternateName(business.name, business.alternateName),
|
|
177
183
|
url: business.url,
|
|
178
184
|
address: postalAddress(business.address),
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
: { openingHoursSpecification: openingHours(business.hours) }),
|
|
199
|
-
...(business.sameAs === undefined ? {} : { sameAs: business.sameAs }),
|
|
200
|
-
...(business.parentOrganization === undefined
|
|
201
|
-
? {}
|
|
202
|
-
: {
|
|
203
|
-
parentOrganization: { "@id": business.parentOrganization },
|
|
204
|
-
}),
|
|
185
|
+
geo:
|
|
186
|
+
business.geo === undefined
|
|
187
|
+
? undefined
|
|
188
|
+
: geoCoordinates(business.geo),
|
|
189
|
+
priceRange: business.priceRange,
|
|
190
|
+
image: listed(business.image)?.map((photo) =>
|
|
191
|
+
absoluteUrl(business.url, photo.src, "venue photo")
|
|
192
|
+
),
|
|
193
|
+
telephone:
|
|
194
|
+
business.telephone === undefined
|
|
195
|
+
? undefined
|
|
196
|
+
: e164(business.telephone),
|
|
197
|
+
email: business.email,
|
|
198
|
+
openingHoursSpecification:
|
|
199
|
+
business.hours === undefined
|
|
200
|
+
? undefined
|
|
201
|
+
: openingHours(business.hours),
|
|
202
|
+
sameAs: business.sameAs,
|
|
203
|
+
parentOrganization: reference(business.parentOrganization),
|
|
205
204
|
};
|
|
206
205
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Quantity } from "../money.ts";
|
|
2
2
|
import type { HttpsUrl } from "../url.ts";
|
|
3
3
|
import type { BusinessId, OrganizationId } from "./ids.ts";
|
|
4
|
-
import { type JsonLdNode, schemaType } from "./node.ts";
|
|
4
|
+
import { type JsonLdNode, listed, reference, schemaType } from "./node.ts";
|
|
5
5
|
import { quantitativeValue } from "./quantity.ts";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -92,19 +92,11 @@ export function creativeWork(work: CreativeWorkInput): JsonLdNode {
|
|
|
92
92
|
"@type": schemaType(["CreativeWork", ...(work.alsoA ?? [])]),
|
|
93
93
|
name: work.name,
|
|
94
94
|
url: work.url,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
? {}
|
|
101
|
-
: { genre: work.genre }),
|
|
102
|
-
...(work.creator === undefined
|
|
103
|
-
? {}
|
|
104
|
-
: { creator: { "@id": work.creator } }),
|
|
105
|
-
...(work.properties === undefined || work.properties.length === 0
|
|
106
|
-
? {}
|
|
107
|
-
: { additionalProperty: work.properties.map(propertyValue) }),
|
|
95
|
+
description: work.description,
|
|
96
|
+
image: work.image,
|
|
97
|
+
genre: listed(work.genre),
|
|
98
|
+
creator: reference(work.creator),
|
|
99
|
+
additionalProperty: listed(work.properties)?.map(propertyValue),
|
|
108
100
|
};
|
|
109
101
|
}
|
|
110
102
|
|
|
@@ -114,12 +106,8 @@ function propertyValue(property: CreativeWorkProperty): JsonLdNode {
|
|
|
114
106
|
name: property.name,
|
|
115
107
|
value: {
|
|
116
108
|
...quantitativeValue(property.value),
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
: { unitCode: property.unitCode }),
|
|
120
|
-
...(property.unitText === undefined
|
|
121
|
-
? {}
|
|
122
|
-
: { unitText: property.unitText }),
|
|
109
|
+
unitCode: property.unitCode,
|
|
110
|
+
unitText: property.unitText,
|
|
123
111
|
},
|
|
124
112
|
};
|
|
125
113
|
}
|
package/src/jsonld/node.ts
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import { literal } from "../analytics/tags.ts";
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* A node in the graph. Deliberately loose: `@type` is what a consumer varies.
|
|
12
|
+
*
|
|
13
|
+
* An optional field it lacks is written as `undefined`, never branched around
|
|
14
|
+
* with a conditional spread: `serializeJsonLd` goes through JSON, which drops
|
|
15
|
+
* it, so the published node has no such key either way.
|
|
16
|
+
*/
|
|
11
17
|
export interface JsonLdNode {
|
|
12
18
|
readonly "@type": string | readonly string[];
|
|
13
19
|
readonly [key: string]: unknown;
|
|
@@ -47,8 +53,8 @@ export function schemaType(
|
|
|
47
53
|
* engine reads it as *another* name and a repeat of the first one is not that:
|
|
48
54
|
* it widens nothing and is one more string to reconcile. Decided here rather
|
|
49
55
|
* than by the caller — three nodes take the field, the rule is the same on all
|
|
50
|
-
* of them, and a project asked to write `
|
|
51
|
-
* one is being handed lib's rule to enforce by hand.
|
|
56
|
+
* of them, and a project asked to write `alt === name ? undefined : alt` at
|
|
57
|
+
* each one is being handed lib's rule to enforce by hand.
|
|
52
58
|
*
|
|
53
59
|
* Which makes `alternateName: brand.name` safe to pass unconditionally: a venue
|
|
54
60
|
* whose name already *is* the brand's simply emits nothing.
|
|
@@ -56,10 +62,34 @@ export function schemaType(
|
|
|
56
62
|
export function alternateName(
|
|
57
63
|
name: string,
|
|
58
64
|
alternate: string | undefined
|
|
59
|
-
):
|
|
60
|
-
return alternate === undefined
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
): string | undefined {
|
|
66
|
+
return alternate === name ? undefined : alternate;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A pointer to a node published elsewhere in the graph, or nothing.
|
|
71
|
+
*
|
|
72
|
+
* Every field built from it is optional, and an `undefined` field is dropped
|
|
73
|
+
* when the graph is serialised: so a node can write `author:
|
|
74
|
+
* reference(item.author)` without a branch.
|
|
75
|
+
*/
|
|
76
|
+
export function reference<Id extends string>(
|
|
77
|
+
id: Id | undefined
|
|
78
|
+
): { readonly "@id": Id } | undefined {
|
|
79
|
+
return id === undefined ? undefined : { "@id": id };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A list, or nothing when it is empty.
|
|
84
|
+
*
|
|
85
|
+
* An empty list is not a set of nothing, it is a field saying nothing — a
|
|
86
|
+
* claim to have been asked and had no answer — so it is left out like any
|
|
87
|
+
* other absent field.
|
|
88
|
+
*/
|
|
89
|
+
export function listed<T>(
|
|
90
|
+
list: readonly T[] | undefined
|
|
91
|
+
): readonly T[] | undefined {
|
|
92
|
+
return list === undefined || list.length === 0 ? undefined : list;
|
|
63
93
|
}
|
|
64
94
|
|
|
65
95
|
/** The graph, serialised for a `<script type="application/ld+json">`. */
|