|
1 | 1 | import { Dynamic } from '@solidjs/web' |
2 | | -import { mapAsync, mapValues } from 'es-toolkit' |
| 2 | +import { mapAsync, mapValues, sample } from 'es-toolkit' |
3 | 3 | import { |
4 | 4 | createMemo, |
5 | 5 | createStore, |
@@ -147,19 +147,50 @@ function Attempt<T extends Schema, V extends 'base' | 'feedback'>(schema: T, sta |
147 | 147 | ) |
148 | 148 | } |
149 | 149 |
|
| 150 | +function Param<T extends boolean>(transform: T) { |
| 151 | + const value = v.union([v.number(), v.string()]) |
| 152 | + const base = v.array(value) |
| 153 | + const withTransform = v.pipe(base, v.transform(sample)) |
| 154 | + return (transform ? withTransform : base) as T extends true ? typeof withTransform : typeof base |
| 155 | +} |
| 156 | + |
| 157 | +function Params<T extends boolean>(transform: T) { |
| 158 | + return v.record(v.string(), Param(transform)) |
| 159 | +} |
| 160 | + |
150 | 161 | export function buildSchemas<T extends Schema>( |
151 | 162 | schema: T, |
152 | 163 | feedback: ReturnType<typeof defineFeedback<T>>, |
153 | 164 | ) { |
154 | 165 | return { |
| 166 | + Teacher: v.object({ |
| 167 | + name: v.literal(schema.name as T['name']), |
| 168 | + question: RawShapeSchema(schema.question as T['question'], 'base'), |
| 169 | + params: v.optional(Params(false)), |
| 170 | + }), |
155 | 171 | Student: v.pipeAsync( |
156 | 172 | v.object({ |
157 | 173 | name: v.literal(schema.name as T['name']), |
158 | 174 | question: RawShapeSchema(schema.question as T['question'], 'base'), |
159 | 175 | attempt: Attempt(schema, 'base'), |
| 176 | + params: v.optional(Params(true)), |
160 | 177 | }), |
161 | 178 | // TODO: calls need to be deduped, waiting for solid-router release? |
162 | | - v.transformAsync(async ({ attempt, question, ...exercise }) => { |
| 179 | + v.transformAsync(async ({ attempt, question: q, params, ...exercise }) => { |
| 180 | + let question = q |
| 181 | + function subs<T extends any>(param: string, value: string, v: T): T { |
| 182 | + if (typeof v === 'string') { |
| 183 | + return v.replaceAll(`{${param}}`, value) as T |
| 184 | + } else if (Array.isArray(v)) { |
| 185 | + return v.map(subs.bind(null, param, value)) as T |
| 186 | + } else if (typeof v === 'object' && v !== null) { |
| 187 | + return mapValues(v, subs.bind(null, param, value)) as T |
| 188 | + } |
| 189 | + return v |
| 190 | + } |
| 191 | + for (const [param, value] of Object.entries(params ?? {})) { |
| 192 | + question = subs(param, String(value), question) |
| 193 | + } |
163 | 194 | const parsedQuestion = v.parse( |
164 | 195 | RawShapeSchema(schema.question as T['question'], 'feedback'), |
165 | 196 | question, |
|
0 commit comments