Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from WICG:main #7

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ara-tester-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ The usefulness of this page depends on testers sharing information and updates;
| MiQ | Adtech & Managed service | From 01.01.2024 | coming soon | [email protected] |
| KelkooGroup | Adtech services for affiliate marketing | From 01.12.2023 | | [email protected] |
| Quantcast | Demand-side platform (DSP) | Testing ongoing | | [email protected] |
| Optable | Adtech services | Testing ongoing | | [email protected] |

## Table - Publishers and Advertisers Interested in Testing or Early Adoption
Companies who may be interested in participating in tests and early adoption opportunities provided by ad tech companies.
Expand Down
17 changes: 9 additions & 8 deletions ts/src/header-validator/maybe.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
export type Maybeable<T> = T | Maybe<T>

export class Maybe<T> {
static readonly None = new Maybe<never>()

static some<T>(this: void, t: T): Maybe<T> {
return new Maybe(t)
}

static flatten<T>(this: void, t: Maybeable<T>): Maybe<T> {
return t instanceof Maybe ? t : Maybe.some(t)
}

private constructor(private readonly t?: T) {}

filter<C extends unknown[]>(
Expand All @@ -21,10 +15,17 @@ export class Maybe<T> {
}

map<U, C extends unknown[]>(
f: (t: T, ...args: C) => Maybeable<U>,
f: (t: T, ...args: C) => U,
...args: C
): Maybe<U> {
return this.t === undefined ? Maybe.None : new Maybe<U>(f(this.t, ...args))
}

flatMap<U, C extends unknown[]>(
f: (t: T, ...args: C) => Maybe<U>,
...args: C
): Maybe<U> {
return this.t === undefined ? Maybe.None : Maybe.flatten(f(this.t, ...args))
return this.t === undefined ? Maybe.None : f(this.t, ...args)
}

peek<C extends unknown[]>(f: (t: T, ...args: C) => void, ...args: C): this {
Expand Down
33 changes: 18 additions & 15 deletions ts/src/header-validator/validate-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class SourceContext extends RegistrationContext {
const {
exclusive,
field,
fieldMaybeDefault,
struct: structInternal,
} = validate.make<JsonDict, Json>(
/*getAndDelete=*/ (d, name) => {
Expand All @@ -86,7 +87,7 @@ function struct<T extends object, C extends Context>(
fields: StructFields<T, C>,
warnUnknown: boolean = true
): Maybe<T> {
return object(d, ctx).map(structInternal, ctx, fields, warnUnknown)
return object(d, ctx).flatMap(structInternal, ctx, fields, warnUnknown)
}

type TypeSwitch<T, C extends Context = Context> = {
Expand Down Expand Up @@ -147,7 +148,7 @@ function keyValues<V, C extends Context = Context>(
f: CtxFunc<C, [key: string, val: Json], Maybe<V>>,
maxKeys: number = Infinity
): Maybe<Map<string, V>> {
return object(j, ctx).map((d) => {
return object(j, ctx).flatMap((d) => {
const entries = Object.entries(d)

if (entries.length > maxKeys) {
Expand Down Expand Up @@ -220,7 +221,7 @@ function destination(j: Json, ctx: Context): Maybe<Set<string>> {
return typeSwitch(j, ctx, {
string: (j) => suitableSite(j, ctx).map((s) => new Set([s])),
list: (j) =>
set(j, ctx, (j) => string(j, ctx).map(suitableSite, ctx), {
set(j, ctx, (j) => string(j, ctx).flatMap(suitableSite, ctx), {
minLength: 1,
maxLength: 3,
}),
Expand Down Expand Up @@ -311,7 +312,7 @@ function eventReportWindows(
ctx: SourceContext,
expiry: Maybe<number>
): Maybe<EventReportWindows> {
return object(j, ctx).map((j) => {
return object(j, ctx).flatMap((j) => {
const startTimeValue = field(
'start_time',
(j) => startTime(j, ctx, expiry),
Expand Down Expand Up @@ -348,7 +349,7 @@ function set<T extends number | string, C extends Context = Context>(
// checks should be performed on the resulting set, not on the list.
return list(j, ctx)
.filter((js) => isLengthValid(js.length, ctx, opts))
.map((js) => validate.set(js.entries(), ctx, f, opts?.requireDistinct))
.flatMap((js) => validate.set(js.entries(), ctx, f, opts?.requireDistinct))
}

type ArrayOpts = LengthOpts & {
Expand All @@ -363,7 +364,9 @@ function array<T, C extends Context = Context>(
): Maybe<T[]> {
return list(j, ctx)
.filter((js) => isLengthValid(js.length, ctx, opts))
.map((js) => validate.array(js.entries(), ctx, f, opts?.itemErrorAction))
.flatMap((js) =>
validate.array(js.entries(), ctx, f, opts?.itemErrorAction)
)
}

function filterDataKeyValue(
Expand Down Expand Up @@ -861,13 +864,13 @@ function triggerSpec(
)

return struct(j, ctx, {
eventReportWindows: field(
eventReportWindows: fieldMaybeDefault(
'event_report_windows',
(j) => eventReportWindows(j, ctx, deps.expiry),
deps.eventReportWindows
),

summaryBuckets: field(
summaryBuckets: fieldMaybeDefault(
'summary_buckets',
(j) => summaryBuckets(j, ctx, deps.maxEventLevelReports),
defaultSummaryBuckets
Expand Down Expand Up @@ -952,7 +955,7 @@ function defaultTriggerSpecs(
eventReportWindows: Maybe<EventReportWindows>,
maxEventLevelReports: Maybe<number>
): Maybe<TriggerSpec[]> {
return eventReportWindows.map((eventReportWindows) =>
return eventReportWindows.flatMap((eventReportWindows) =>
maxEventLevelReports.map((maxEventLevelReports) => [
{
eventReportWindows,
Expand Down Expand Up @@ -1048,7 +1051,7 @@ export type Source = CommonDebug &

function source(j: Json, ctx: SourceContext): Maybe<Source> {
return object(j, ctx)
.map((j) => {
.flatMap((j) => {
const expiryVal = field(
'expiry',
expiry,
Expand Down Expand Up @@ -1095,7 +1098,7 @@ function source(j: Json, ctx: SourceContext): Maybe<Source> {
)(j, ctx)

return struct(j, ctx, {
aggregatableReportWindow: field(
aggregatableReportWindow: fieldMaybeDefault(
'aggregatable_report_window',
(j) => singleReportWindow(j, ctx, expiryVal),
expiryVal
Expand Down Expand Up @@ -1258,7 +1261,7 @@ function aggregatableDedupKeys(
}

function enumerated<T>(j: Json, ctx: Context, e: Record<string, T>): Maybe<T> {
return string(j, ctx).map(validate.enumerated, ctx, e)
return string(j, ctx).flatMap(validate.enumerated, ctx, e)
}

export enum AggregatableSourceRegistrationTime {
Expand Down Expand Up @@ -1348,7 +1351,7 @@ function aggregationCoordinatorOrigin(
ctx: RegistrationContext
): Maybe<string> {
return string(j, ctx)
.map(suitableOrigin, ctx)
.flatMap(suitableOrigin, ctx)
.filter((s) => {
if (!ctx.vsv.aggregationCoordinatorOrigins.includes(s)) {
const allowed = ctx.vsv.aggregationCoordinatorOrigins.join(', ')
Expand All @@ -1373,7 +1376,7 @@ export type Trigger = CommonDebug &

function trigger(j: Json, ctx: RegistrationContext): Maybe<Trigger> {
return object(j, ctx)
.map((j) => {
.flatMap((j) => {
const aggregatableSourceRegTimeVal = field(
'aggregatable_source_registration_time',
aggregatableSourceRegistrationTime,
Expand Down Expand Up @@ -1483,7 +1486,7 @@ function reportDestination(j: Json, ctx: Context): Maybe<string | string[]> {
return typeSwitch<string | string[]>(j, ctx, {
string: suitableSiteNoExtraneous,
list: (j) =>
array(j, ctx, (j) => string(j, ctx).map(suitableSiteNoExtraneous), {
array(j, ctx, (j) => string(j, ctx).flatMap(suitableSiteNoExtraneous), {
minLength: 2,
maxLength: 3,
}).filter((v) => {
Expand Down
42 changes: 35 additions & 7 deletions ts/src/header-validator/validate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as psl from 'psl'
import { Context, PathComponent } from './context'
import { Maybe, Maybeable } from './maybe'
import { Maybe } from './maybe'

export type CtxFunc<C extends Context, I, O> = (i: I, ctx: C) => O

Expand Down Expand Up @@ -52,14 +52,14 @@ type GetAndDeleteFunc<D, V> = (d: D, name: string) => V | undefined
type FieldFunc<D, V> = <T, C extends Context>(
name: string,
f: CtxFunc<C, V, Maybe<T>>,
valueIfAbsent?: Maybeable<T>
valueIfAbsent?: T
) => CtxFunc<C, D, Maybe<T>>

function field<D, V>(getAndDelete: GetAndDeleteFunc<D, V>): FieldFunc<D, V> {
return <T, C extends Context>(
name: string,
f: CtxFunc<C, V, Maybe<T>>,
valueIfAbsent?: Maybeable<T>
valueIfAbsent?: T
) =>
(d: D, ctx: C): Maybe<T> =>
ctx.scope(name, () => {
Expand All @@ -69,7 +69,33 @@ function field<D, V>(getAndDelete: GetAndDeleteFunc<D, V>): FieldFunc<D, V> {
ctx.error('required')
return Maybe.None
}
return Maybe.flatten(valueIfAbsent)
return Maybe.some(valueIfAbsent)
}
return f(v, ctx)
})
}

type FieldMaybeDefaultFunc<D, V> = <T, C extends Context>(
name: string,
f: CtxFunc<C, V, Maybe<T>>,
valueIfAbsent: Maybe<T>
) => CtxFunc<C, D, Maybe<T>>

// TODO(apaseltiner): Merge this function back into `field` since it is
// identical other than whether the default value is T or Maybe<T>.
function fieldMaybeDefault<D, V>(
getAndDelete: GetAndDeleteFunc<D, V>
): FieldMaybeDefaultFunc<D, V> {
return <T, C extends Context>(
name: string,
f: CtxFunc<C, V, Maybe<T>>,
valueIfAbsent: Maybe<T>
) =>
(d: D, ctx: C): Maybe<T> =>
ctx.scope(name, () => {
const v = getAndDelete(d, name)
if (v === undefined) {
return valueIfAbsent
}
return f(v, ctx)
})
Expand All @@ -81,15 +107,15 @@ export type Exclusive<T, V, C extends Context> = {

type ExclusiveFunc<D, V> = <T, C extends Context>(
x: Exclusive<T, V, C>,
valueIfAbsent: Maybeable<T>
valueIfAbsent: Maybe<T>
) => CtxFunc<C, D, Maybe<T>>

function exclusive<D, V>(
getAndDelete: GetAndDeleteFunc<D, V>
): ExclusiveFunc<D, V> {
return <T, C extends Context>(
x: Exclusive<T, V, C>,
valueIfAbsent: Maybeable<T>
valueIfAbsent: Maybe<T>
) =>
(d: D, ctx: C): Maybe<T> => {
const found: string[] = []
Expand All @@ -112,13 +138,14 @@ function exclusive<D, V>(
return Maybe.None
}

return Maybe.flatten(valueIfAbsent)
return valueIfAbsent
}
}

type Funcs<D, V> = {
exclusive: ExclusiveFunc<D, V>
field: FieldFunc<D, V>
fieldMaybeDefault: FieldMaybeDefaultFunc<D, V>
struct: StructFunc<D>
}

Expand All @@ -130,6 +157,7 @@ export function make<D, V>(
return {
exclusive: exclusive(getAndDelete),
field: field(getAndDelete),
fieldMaybeDefault: fieldMaybeDefault(getAndDelete),
struct: struct(unknownKeys, warnUnknownMsg),
}
}
Expand Down
Loading