@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21
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/package.json +62 -36
- package/src/cli.js +15 -12
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +66 -72
- package/src/core/adapt/index.js +17 -6
- package/src/core/config/index.js +134 -80
- package/src/core/config/options.js +295 -273
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +146 -16
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +8 -20
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +4 -2
- package/src/core/postbuild/prerender.js +222 -70
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +82 -62
- package/src/core/sync/sync.js +40 -31
- package/src/core/sync/ts.js +1 -1
- package/src/core/sync/utils.js +22 -2
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
- package/src/core/sync/write_client_manifest.js +14 -29
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +37 -45
- package/src/core/sync/write_tsconfig/index.js +274 -0
- package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
- package/src/core/sync/write_tsconfig/utils.js +77 -0
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +127 -123
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/env/public.d.ts +55 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/public.d.ts +195 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +52 -29
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +8 -5
- package/src/exports/internal/index.js +1 -90
- package/src/exports/internal/{event.js → server/event.js} +2 -3
- package/src/exports/internal/server/index.js +37 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/internal/shared.js +90 -0
- package/src/exports/node/index.js +64 -22
- package/src/exports/params/index.js +70 -0
- package/src/exports/params/public.d.ts +63 -0
- package/src/exports/public.d.ts +50 -1733
- package/src/exports/remote/index.js +11 -0
- package/src/exports/remote/public.d.ts +519 -0
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +54 -65
- package/src/exports/vite/build/remote.js +24 -19
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +218 -146
- package/src/exports/vite/index.js +1590 -858
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +40 -32
- package/src/exports/vite/public.d.ts +588 -0
- package/src/exports/vite/utils.js +84 -46
- package/src/pathname.js +55 -0
- package/src/runner.js +15 -0
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/env/types.d.ts +1 -1
- package/src/runtime/app/environment/index.js +3 -3
- package/src/runtime/app/{forms.js → forms/index.js} +73 -42
- package/src/runtime/app/forms/public.d.ts +2 -0
- package/src/runtime/app/forms/types.d.ts +56 -0
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
- package/src/runtime/app/navigation/public.d.ts +237 -0
- package/src/runtime/app/paths/client.js +37 -37
- package/src/runtime/app/paths/index.js +1 -1
- package/src/runtime/app/paths/internal/client.js +34 -2
- package/src/runtime/app/paths/internal/server.js +6 -23
- package/src/runtime/app/paths/internal.d.ts +3 -0
- package/src/runtime/app/paths/public.d.ts +1 -29
- package/src/runtime/app/paths/server.js +36 -17
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/index.js +2 -2
- package/src/runtime/app/server/public.d.ts +201 -0
- package/src/runtime/app/server/remote/command.js +13 -11
- package/src/runtime/app/server/remote/form.js +61 -39
- package/src/runtime/app/server/remote/prerender.js +45 -45
- package/src/runtime/app/server/remote/query.js +106 -108
- package/src/runtime/app/server/remote/requested.js +27 -19
- package/src/runtime/app/server/remote/shared.js +76 -76
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +4 -2
- package/src/runtime/app/state/index.js +7 -5
- package/src/runtime/app/state/public.d.ts +72 -0
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/app/stores.js +15 -78
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +1336 -648
- package/src/runtime/client/constants.js +3 -6
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +25 -25
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/parse.js +1 -1
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/command.svelte.js +37 -61
- package/src/runtime/client/remote-functions/form.svelte.js +267 -178
- package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
- package/src/runtime/client/remote-functions/query/index.js +10 -17
- package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
- package/src/runtime/client/remote-functions/query/proxy.js +5 -5
- package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
- package/src/runtime/client/remote-functions/query-live/index.js +1 -1
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/client/state.svelte.js +94 -55
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/client/types.d.ts +13 -9
- package/src/runtime/client/utils.js +22 -110
- package/src/runtime/components/root.svelte +56 -0
- package/src/runtime/env/dynamic/private.js +7 -0
- package/src/runtime/env/dynamic/public.js +7 -0
- package/src/runtime/env/static/private.js +6 -0
- package/src/runtime/env/static/public.js +6 -0
- package/src/runtime/form-utils.js +172 -61
- package/src/runtime/pathname.js +20 -32
- package/src/runtime/props.svelte.js +72 -0
- package/src/runtime/server/constants.js +0 -3
- package/src/runtime/server/cookie.js +72 -55
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +49 -53
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +6 -7
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +32 -39
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +85 -64
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/data_serializer.js +24 -25
- package/src/runtime/server/page/index.js +36 -53
- package/src/runtime/server/page/load_data.js +50 -57
- package/src/runtime/server/page/render.js +173 -239
- package/src/runtime/server/page/respond_with_error.js +17 -31
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +85 -26
- package/src/runtime/server/remote-functions.js +640 -0
- package/src/runtime/server/respond.js +190 -131
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +13 -155
- package/src/runtime/shared.js +20 -40
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +11 -1
- package/src/types/ambient.d.ts +87 -36
- package/src/types/global-private.d.ts +25 -25
- package/src/types/internal.d.ts +163 -157
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +28 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/filesystem.js +1 -23
- package/src/utils/fork.js +7 -2
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +9 -2
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +6 -7
- package/src/utils/params.js +67 -0
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +145 -73
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +33 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +2616 -2433
- package/types/index.d.ts.map +120 -106
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_root.js +0 -148
- package/src/core/sync/write_tsconfig.js +0 -250
- package/src/exports/internal/server.js +0 -22
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
- /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
|
@@ -3,62 +3,100 @@
|
|
|
3
3
|
|
|
4
4
|
import { DEV } from 'esm-env';
|
|
5
5
|
import * as devalue from 'devalue';
|
|
6
|
-
import { text_encoder } from './utils.js';
|
|
6
|
+
import { text_decoder, text_encoder } from './utils.js';
|
|
7
|
+
import { noop } from '../utils/functions.js';
|
|
7
8
|
import { SvelteKitError } from '@sveltejs/kit/internal';
|
|
8
9
|
|
|
9
|
-
const decoder = new TextDecoder();
|
|
10
|
-
|
|
11
10
|
/**
|
|
12
|
-
* Sets a value in a nested object
|
|
11
|
+
* Sets a parsed form field value in a nested object, mutating the original object.
|
|
13
12
|
* @param {Record<string, any>} object
|
|
14
|
-
* @param {string}
|
|
13
|
+
* @param {{ name: string; type: 'number' | 'boolean' | null }} field
|
|
15
14
|
* @param {any} value
|
|
16
15
|
*/
|
|
17
|
-
export function set_nested_value(object,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
export function set_nested_value(object, field, value) {
|
|
17
|
+
deep_set(object, split_path(field.name), value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Separates a form field's path from the metadata encoded in its name.
|
|
22
|
+
* @param {string} form_id
|
|
23
|
+
* @param {string} key
|
|
24
|
+
* @returns {{ name: string; type: 'number' | 'boolean' | null; is_array: boolean }}
|
|
25
|
+
*/
|
|
26
|
+
export function parse_form_key(form_id, key) {
|
|
27
|
+
const suffix = '/' + form_id;
|
|
28
|
+
let name = key;
|
|
29
|
+
|
|
30
|
+
if (!name.endsWith(suffix)) {
|
|
31
|
+
throw new Error(`Form contained a field that wasn't created with form.fields.as(...): ${name}`);
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
name = name.slice(0, -suffix.length);
|
|
35
|
+
|
|
36
|
+
/** @type {'number' | 'boolean' | null} */
|
|
37
|
+
let type = null;
|
|
38
|
+
|
|
39
|
+
if (name.startsWith('n:')) {
|
|
40
|
+
name = name.slice(2);
|
|
41
|
+
type = 'number';
|
|
42
|
+
} else if (name.startsWith('b:')) {
|
|
43
|
+
name = name.slice(2);
|
|
44
|
+
type = 'boolean';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const is_array = name.endsWith('[]');
|
|
48
|
+
if (is_array) name = name.slice(0, -2);
|
|
49
|
+
|
|
50
|
+
return { name, type, is_array };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {'number' | 'boolean' | null} type
|
|
55
|
+
* @param {any} value
|
|
56
|
+
* @returns {any}
|
|
57
|
+
*/
|
|
58
|
+
export function coerce_form_value(type, value) {
|
|
59
|
+
if (Array.isArray(value)) return value.map((value) => coerce_form_value(type, value));
|
|
60
|
+
if (type === 'number') return value === '' ? undefined : parseFloat(value);
|
|
61
|
+
if (type === 'boolean') return value === 'on';
|
|
62
|
+
return value;
|
|
27
63
|
}
|
|
28
64
|
|
|
65
|
+
/** Pass this to set_nested_value to delete the last part of the given path */
|
|
66
|
+
export const DELETE_KEY = {};
|
|
67
|
+
|
|
29
68
|
/**
|
|
30
69
|
* Convert `FormData` into a POJO
|
|
70
|
+
* @param {string} form_id
|
|
31
71
|
* @param {FormData} data
|
|
32
72
|
*/
|
|
33
|
-
export function convert_formdata(data) {
|
|
73
|
+
export function convert_formdata(form_id, data) {
|
|
34
74
|
/** @type {Record<string, any>} */
|
|
35
75
|
const result = {};
|
|
36
76
|
|
|
37
|
-
for (
|
|
38
|
-
const is_array = key.endsWith('[]');
|
|
77
|
+
for (const field_name of data.keys()) {
|
|
39
78
|
/** @type {any[]} */
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (is_array) key = key.slice(0, -2);
|
|
79
|
+
const values = data.getAll(field_name);
|
|
43
80
|
|
|
44
|
-
|
|
45
|
-
throw new Error(`Form cannot contain duplicated keys — "${key}" has ${values.length} values`);
|
|
46
|
-
}
|
|
81
|
+
const field = parse_form_key(form_id, field_name);
|
|
47
82
|
|
|
48
83
|
// an empty `<input type="file">` will submit a non-existent file, bizarrely
|
|
49
|
-
|
|
84
|
+
const entries = values.filter(
|
|
50
85
|
(entry) => typeof entry === 'string' || entry.name !== '' || entry.size > 0
|
|
51
86
|
);
|
|
87
|
+
if (entries.length === 0 && !field.is_array) continue;
|
|
52
88
|
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
key = key.slice(2);
|
|
58
|
-
values = values.map((v) => v === 'on');
|
|
89
|
+
if (entries.length > 1 && !field.is_array) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Form cannot contain duplicated keys — "${field.name}" has ${entries.length} values`
|
|
92
|
+
);
|
|
59
93
|
}
|
|
60
94
|
|
|
61
|
-
set_nested_value(
|
|
95
|
+
set_nested_value(
|
|
96
|
+
result,
|
|
97
|
+
field,
|
|
98
|
+
coerce_form_value(field.type, field.is_array ? entries : entries[0])
|
|
99
|
+
);
|
|
62
100
|
}
|
|
63
101
|
|
|
64
102
|
return result;
|
|
@@ -134,21 +172,19 @@ export function serialize_binary_form(data, meta) {
|
|
|
134
172
|
|
|
135
173
|
/**
|
|
136
174
|
* @param {Request} request
|
|
175
|
+
* @param {string} form_id
|
|
137
176
|
* @returns {Promise<{ data: Record<string, any>; meta: BinaryFormMeta; form_data: FormData | null }>}
|
|
138
177
|
*/
|
|
139
|
-
export async function deserialize_binary_form(request) {
|
|
178
|
+
export async function deserialize_binary_form(request, form_id) {
|
|
140
179
|
if (request.headers.get('content-type') !== BINARY_FORM_CONTENT_TYPE) {
|
|
141
180
|
const form_data = await request.formData();
|
|
142
|
-
return { data: convert_formdata(form_data), meta: {}, form_data };
|
|
181
|
+
return { data: convert_formdata(form_id, form_data), meta: {}, form_data };
|
|
143
182
|
}
|
|
144
183
|
if (!request.body) {
|
|
145
184
|
throw deserialize_error('no body');
|
|
146
185
|
}
|
|
147
186
|
|
|
148
|
-
|
|
149
|
-
const reader = /** @type {ReadableStreamDefaultReader<Uint8Array<ArrayBuffer>>} */ (
|
|
150
|
-
request.body.getReader()
|
|
151
|
-
);
|
|
187
|
+
const reader = request.body.getReader();
|
|
152
188
|
|
|
153
189
|
/** @type {Array<Promise<Uint8Array<ArrayBuffer> | undefined>>} */
|
|
154
190
|
const chunks = [];
|
|
@@ -245,7 +281,7 @@ export async function deserialize_binary_form(request) {
|
|
|
245
281
|
const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
|
|
246
282
|
if (!file_offsets_buffer) throw deserialize_error('file offset table too short');
|
|
247
283
|
|
|
248
|
-
const parsed_offsets = JSON.parse(
|
|
284
|
+
const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));
|
|
249
285
|
|
|
250
286
|
if (
|
|
251
287
|
!Array.isArray(parsed_offsets) ||
|
|
@@ -260,7 +296,7 @@ export async function deserialize_binary_form(request) {
|
|
|
260
296
|
|
|
261
297
|
/** @type {Array<{ offset: number, size: number }>} */
|
|
262
298
|
const file_spans = [];
|
|
263
|
-
const [data, meta] = devalue.parse(
|
|
299
|
+
const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
|
|
264
300
|
File: ([name, type, size, last_modified, index]) => {
|
|
265
301
|
if (
|
|
266
302
|
typeof name !== 'string' ||
|
|
@@ -319,7 +355,7 @@ export async function deserialize_binary_form(request) {
|
|
|
319
355
|
const chunk = await get_chunk(chunks.length);
|
|
320
356
|
has_more = !!chunk;
|
|
321
357
|
}
|
|
322
|
-
})();
|
|
358
|
+
})().catch(noop); // prevent unhandled rejection potentially crashing the process
|
|
323
359
|
|
|
324
360
|
return { data, meta, form_data: null };
|
|
325
361
|
}
|
|
@@ -450,7 +486,7 @@ class LazyFile {
|
|
|
450
486
|
});
|
|
451
487
|
}
|
|
452
488
|
async text() {
|
|
453
|
-
return
|
|
489
|
+
return text_decoder.decode(await this.arrayBuffer());
|
|
454
490
|
}
|
|
455
491
|
}
|
|
456
492
|
|
|
@@ -503,6 +539,10 @@ export function deep_set(object, keys, value) {
|
|
|
503
539
|
}
|
|
504
540
|
|
|
505
541
|
if (!exists) {
|
|
542
|
+
if (value === DELETE_KEY) {
|
|
543
|
+
// don't create the nested structure if we want to delete the key anyway
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
506
546
|
current[key] = is_array ? [] : {};
|
|
507
547
|
}
|
|
508
548
|
|
|
@@ -511,7 +551,12 @@ export function deep_set(object, keys, value) {
|
|
|
511
551
|
|
|
512
552
|
const final_key = keys[keys.length - 1];
|
|
513
553
|
check_prototype_pollution(final_key);
|
|
514
|
-
|
|
554
|
+
|
|
555
|
+
if (value === DELETE_KEY) {
|
|
556
|
+
delete current[final_key];
|
|
557
|
+
} else {
|
|
558
|
+
current[final_key] = value;
|
|
559
|
+
}
|
|
515
560
|
}
|
|
516
561
|
|
|
517
562
|
/**
|
|
@@ -608,18 +653,56 @@ function get_type_prefix(field_type, is_array, input_value) {
|
|
|
608
653
|
return '';
|
|
609
654
|
}
|
|
610
655
|
|
|
656
|
+
/**
|
|
657
|
+
* A deep-clone implementation specifically for form data, where
|
|
658
|
+
* we don't need to worry about cycles and whatnot
|
|
659
|
+
* @param {any} value
|
|
660
|
+
* @returns {any}
|
|
661
|
+
*/
|
|
662
|
+
function deep_clone(value) {
|
|
663
|
+
if (value !== null && typeof value === 'object') {
|
|
664
|
+
if (value instanceof Date) {
|
|
665
|
+
return new Date(value.getTime());
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (value instanceof File) {
|
|
669
|
+
return value;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (Array.isArray(value)) {
|
|
673
|
+
return value.map(deep_clone);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/** @type {Record<string, any>} */
|
|
677
|
+
const clone = {};
|
|
678
|
+
for (const key of Object.keys(value)) {
|
|
679
|
+
clone[key] = deep_clone(value[key]);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return clone;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return value;
|
|
686
|
+
}
|
|
687
|
+
|
|
611
688
|
/**
|
|
612
689
|
* Creates a proxy-based field accessor for form data
|
|
690
|
+
* @param {{
|
|
691
|
+
* form_id: string,
|
|
692
|
+
* get: () => Record<string, any>,
|
|
693
|
+
* set: (path: (string | number)[], value: any) => void,
|
|
694
|
+
* get_issues: (path?: (string | number)[], all?: boolean) => Record<string, InternalRemoteFormIssue[]>,
|
|
695
|
+
* get_touched: () => Record<string, boolean>,
|
|
696
|
+
* get_dirty: () => Record<string, boolean>
|
|
697
|
+
* }} context - Form context, including value accessors and form metadata
|
|
613
698
|
* @param {any} target - Function or empty POJO
|
|
614
|
-
* @param {() => Record<string, any>} get_input - Function to get current input data
|
|
615
|
-
* @param {(path: (string | number)[], value: any) => void} set_input - Function to set input data
|
|
616
|
-
* @param {(path?: (string | number)[], all?: boolean) => Record<string, InternalRemoteFormIssue[]>} get_issues - Function to get current issues
|
|
617
699
|
* @param {(string | number)[]} path - Current access path
|
|
618
700
|
* @returns {any} Proxy object with name(), value(), and issues() methods
|
|
619
701
|
*/
|
|
620
|
-
export function create_field_proxy(
|
|
702
|
+
export function create_field_proxy(context, target = {}, path = []) {
|
|
621
703
|
const get_value = () => {
|
|
622
|
-
|
|
704
|
+
const value = deep_get(context.get(), path);
|
|
705
|
+
return deep_clone(value);
|
|
623
706
|
};
|
|
624
707
|
|
|
625
708
|
return new Proxy(target, {
|
|
@@ -628,29 +711,27 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
|
|
|
628
711
|
|
|
629
712
|
// Handle array access like jobs[0]
|
|
630
713
|
if (/^\d+$/.test(prop)) {
|
|
631
|
-
return create_field_proxy({},
|
|
632
|
-
...path,
|
|
633
|
-
parseInt(prop, 10)
|
|
634
|
-
]);
|
|
714
|
+
return create_field_proxy(context, {}, [...path, parseInt(prop, 10)]);
|
|
635
715
|
}
|
|
636
716
|
|
|
637
717
|
const key = build_path_string(path);
|
|
718
|
+
const next = [...path, prop];
|
|
638
719
|
|
|
639
720
|
if (prop === 'set') {
|
|
640
721
|
const set_func = function (/** @type {any} */ newValue) {
|
|
641
|
-
|
|
722
|
+
context.set(path, newValue);
|
|
642
723
|
return newValue;
|
|
643
724
|
};
|
|
644
|
-
return create_field_proxy(
|
|
725
|
+
return create_field_proxy(context, set_func, next);
|
|
645
726
|
}
|
|
646
727
|
|
|
647
728
|
if (prop === 'value') {
|
|
648
|
-
return create_field_proxy(
|
|
729
|
+
return create_field_proxy(context, get_value, next);
|
|
649
730
|
}
|
|
650
731
|
|
|
651
732
|
if (prop === 'issues' || prop === 'allIssues') {
|
|
652
733
|
const issues_func = () => {
|
|
653
|
-
const all_issues = get_issues(path, prop === 'allIssues')[key === '' ? '$' : key];
|
|
734
|
+
const all_issues = context.get_issues(path, prop === 'allIssues')[key === '' ? '$' : key];
|
|
654
735
|
|
|
655
736
|
if (prop === 'allIssues') {
|
|
656
737
|
return all_issues?.map((issue) => ({
|
|
@@ -659,15 +740,45 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
|
|
|
659
740
|
}));
|
|
660
741
|
}
|
|
661
742
|
|
|
662
|
-
|
|
743
|
+
const issues = all_issues
|
|
663
744
|
?.filter((issue) => issue.name === key)
|
|
664
745
|
?.map((issue) => ({
|
|
665
746
|
path: issue.path,
|
|
666
747
|
message: issue.message
|
|
667
748
|
}));
|
|
749
|
+
|
|
750
|
+
return issues?.length ? issues : undefined;
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
return create_field_proxy(context, issues_func, next);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (prop === 'touched' || prop === 'dirty') {
|
|
757
|
+
const fn = () => {
|
|
758
|
+
const object = prop === 'dirty' ? context.get_dirty() : context.get_touched();
|
|
759
|
+
|
|
760
|
+
if (key === '') {
|
|
761
|
+
return Object.keys(object).length > 0;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (Object.hasOwn(object, key)) {
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
for (const candidate in object) {
|
|
769
|
+
if (!Object.hasOwn(object, candidate)) continue;
|
|
770
|
+
if (!candidate.startsWith(key)) continue;
|
|
771
|
+
|
|
772
|
+
const next = candidate[key.length];
|
|
773
|
+
if (next === '.' || next === '[') {
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return false;
|
|
668
779
|
};
|
|
669
780
|
|
|
670
|
-
return create_field_proxy(
|
|
781
|
+
return create_field_proxy(context, fn, next);
|
|
671
782
|
}
|
|
672
783
|
|
|
673
784
|
if (prop === 'as') {
|
|
@@ -681,14 +792,14 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
|
|
|
681
792
|
type === 'select multiple' ||
|
|
682
793
|
(type === 'checkbox' && typeof input_value === 'string');
|
|
683
794
|
|
|
684
|
-
const
|
|
795
|
+
const type_prefix = get_type_prefix(type, is_array, input_value);
|
|
685
796
|
|
|
686
797
|
// Base properties for all input types
|
|
687
798
|
/** @type {Record<string, any>} */
|
|
688
799
|
const base_props = {
|
|
689
|
-
name:
|
|
800
|
+
name: type_prefix + key + (is_array ? '[]' : '') + '/' + context.form_id,
|
|
690
801
|
get 'aria-invalid'() {
|
|
691
|
-
const issues = get_issues();
|
|
802
|
+
const issues = context.get_issues();
|
|
692
803
|
return key in issues ? 'true' : undefined;
|
|
693
804
|
}
|
|
694
805
|
};
|
|
@@ -833,11 +944,11 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
|
|
|
833
944
|
});
|
|
834
945
|
};
|
|
835
946
|
|
|
836
|
-
return create_field_proxy(
|
|
947
|
+
return create_field_proxy(context, as_func, next);
|
|
837
948
|
}
|
|
838
949
|
|
|
839
950
|
// Handle property access (nested fields)
|
|
840
|
-
return create_field_proxy({},
|
|
951
|
+
return create_field_proxy(context, {}, next);
|
|
841
952
|
}
|
|
842
953
|
});
|
|
843
954
|
}
|
package/src/runtime/pathname.js
CHANGED
|
@@ -1,49 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { app_dir, base } from '#app/paths';
|
|
2
|
+
import { add_resolution_suffix } from '../pathname.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
export function has_data_suffix(pathname) {
|
|
6
|
-
return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** @param {string} pathname */
|
|
10
|
-
export function add_data_suffix(pathname) {
|
|
11
|
-
if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX);
|
|
12
|
-
return pathname.replace(/\/$/, '') + DATA_SUFFIX;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** @param {string} pathname */
|
|
16
|
-
export function strip_data_suffix(pathname) {
|
|
17
|
-
if (pathname.endsWith(HTML_DATA_SUFFIX)) {
|
|
18
|
-
return pathname.slice(0, -HTML_DATA_SUFFIX.length) + '.html';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return pathname.slice(0, -DATA_SUFFIX.length);
|
|
22
|
-
}
|
|
4
|
+
export * from '../pathname.js';
|
|
23
5
|
|
|
24
|
-
const
|
|
6
|
+
const ROUTES_PREFIX = '/routes';
|
|
25
7
|
|
|
26
8
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
9
|
+
* The pathname of the route-ID-keyed resolution module for a given route ID,
|
|
10
|
+
* e.g. `/_app/routes/blog/[slug]/__route.js` (before prefixing with `base`).
|
|
11
|
+
* @param {string} route_id
|
|
12
|
+
* @returns {string}
|
|
29
13
|
*/
|
|
30
|
-
export function
|
|
31
|
-
return
|
|
14
|
+
export function route_id_resolution_pathname(route_id) {
|
|
15
|
+
return add_resolution_suffix(`/${app_dir}${ROUTES_PREFIX}${route_id === '/' ? '' : route_id}`);
|
|
32
16
|
}
|
|
33
17
|
|
|
34
18
|
/**
|
|
35
|
-
*
|
|
19
|
+
* Whether a pathname (with the `/__route.js` suffix already stripped, and `base` NOT yet stripped)
|
|
20
|
+
* is a route-ID resolution request rather than a pathname resolution request.
|
|
36
21
|
* @param {string} pathname
|
|
37
|
-
* @returns {
|
|
22
|
+
* @returns {boolean}
|
|
38
23
|
*/
|
|
39
|
-
export function
|
|
40
|
-
|
|
24
|
+
export function is_route_id_resolution_path(pathname) {
|
|
25
|
+
const prefix = `${base}/${app_dir}${ROUTES_PREFIX}`;
|
|
26
|
+
return pathname === prefix || pathname.startsWith(prefix + '/');
|
|
41
27
|
}
|
|
42
28
|
|
|
43
29
|
/**
|
|
30
|
+
* Extract the route ID from a decoded, base-stripped, suffix-stripped pathname,
|
|
31
|
+
* e.g. `/_app/routes/blog/[slug]` -> `/blog/[slug]`, `/_app/routes` -> `/`.
|
|
44
32
|
* @param {string} pathname
|
|
45
33
|
* @returns {string}
|
|
46
34
|
*/
|
|
47
|
-
export function
|
|
48
|
-
return pathname.slice(
|
|
35
|
+
export function extract_route_id(pathname) {
|
|
36
|
+
return pathname.slice(`/${app_dir}${ROUTES_PREFIX}`.length) || '/';
|
|
49
37
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** @import { Component } from 'svelte'; */
|
|
2
|
+
/** @import { Page } from '$app/state'; */
|
|
3
|
+
|
|
4
|
+
import { noop } from '../utils/functions.js';
|
|
5
|
+
|
|
6
|
+
export class Props {
|
|
7
|
+
/** @type {Page} */
|
|
8
|
+
page;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An array of the `+layout.svelte` and `+page.svelte` component instances
|
|
12
|
+
* that currently live on the page — used for capturing and restoring snapshots.
|
|
13
|
+
* It's updated/manipulated through `bind:this` in `Root.svelte`.
|
|
14
|
+
* @type {Array<Record<string, any>>}
|
|
15
|
+
* @deprecated only used for `export const snapshot` — TODO 4.0 get rid
|
|
16
|
+
*/
|
|
17
|
+
components = [];
|
|
18
|
+
|
|
19
|
+
/** @type {any} */
|
|
20
|
+
form;
|
|
21
|
+
|
|
22
|
+
/** @type {App.Error | undefined} */
|
|
23
|
+
error;
|
|
24
|
+
|
|
25
|
+
/** @type {RenderNode} */
|
|
26
|
+
tree;
|
|
27
|
+
|
|
28
|
+
/** @type {(error: unknown, reset: () => void) => void} */
|
|
29
|
+
onerror;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {{
|
|
33
|
+
* page: Page;
|
|
34
|
+
* tree: RenderNode;
|
|
35
|
+
* form: any;
|
|
36
|
+
* error: App.Error | undefined;
|
|
37
|
+
* onerror?: (error: unknown, reset: () => void) => void;
|
|
38
|
+
* }} props
|
|
39
|
+
*/
|
|
40
|
+
constructor({ page, tree, form, error, onerror = noop }) {
|
|
41
|
+
this.page = page;
|
|
42
|
+
this.tree = tree;
|
|
43
|
+
this.onerror = onerror;
|
|
44
|
+
|
|
45
|
+
this.form = $state.raw(form);
|
|
46
|
+
this.error = $state.raw(error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class RenderNode {
|
|
51
|
+
/** @type {Component} */
|
|
52
|
+
component;
|
|
53
|
+
|
|
54
|
+
/** @type {Component | undefined} */
|
|
55
|
+
error;
|
|
56
|
+
|
|
57
|
+
/** @type {Record<string, any>} */
|
|
58
|
+
data = $state.raw({});
|
|
59
|
+
|
|
60
|
+
/** @type {RenderNode | undefined} */
|
|
61
|
+
child = $state.raw();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @param {Component} component
|
|
66
|
+
* @param {Component} error
|
|
67
|
+
*/
|
|
68
|
+
constructor(component, error) {
|
|
69
|
+
this.component = component;
|
|
70
|
+
this.error = error;
|
|
71
|
+
}
|
|
72
|
+
}
|