@sveltejs/kit 1.0.0-next.220 → 1.0.0-next.224

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.
@@ -225,6 +225,7 @@ async function create_plugin(config, output, cwd) {
225
225
  hooks,
226
226
  hydrate: config.kit.hydrate,
227
227
  manifest,
228
+ method_override: config.kit.methodOverride,
228
229
  paths: {
229
230
  base: config.kit.paths.base,
230
231
  assets: config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base
@@ -234,7 +235,6 @@ async function create_plugin(config, output, cwd) {
234
235
  read: (file) => fs__default.readFileSync(path__default.join(config.kit.files.assets, file)),
235
236
  root,
236
237
  router: config.kit.router,
237
- ssr: config.kit.ssr,
238
238
  target: config.kit.target,
239
239
  template: ({ head, body, assets }) => {
240
240
  let rendered = load_template(cwd, config)
@@ -307,6 +307,7 @@ export class App {
307
307
  hooks,
308
308
  hydrate: ${s(config.kit.hydrate)},
309
309
  manifest,
310
+ method_override: ${s(config.kit.methodOverride)},
310
311
  paths: { base, assets },
311
312
  prefix: assets + '/${config.kit.appDir}/',
312
313
  prerender: ${config.kit.prerender.enabled},
@@ -314,7 +315,6 @@ export class App {
314
315
  root,
315
316
  service_worker: ${has_service_worker ? "'/service-worker.js'" : 'null'},
316
317
  router: ${s(config.kit.router)},
317
- ssr: ${s(config.kit.ssr)},
318
318
  target: ${s(config.kit.target)},
319
319
  template,
320
320
  trailing_slash: ${s(config.kit.trailingSlash)}
@@ -98,58 +98,194 @@ function queue(concurrency) {
98
98
  };
99
99
  }
100
100
 
101
- /**
102
- * @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
103
- * @typedef {import('types/config').PrerenderOnErrorValue} OnError
104
- * @typedef {import('types/internal').Logger} Logger
105
- */
101
+ const DOCTYPE = 'DOCTYPE';
102
+ const CDATA_OPEN = '[CDATA[';
103
+ const CDATA_CLOSE = ']]>';
104
+ const COMMENT_OPEN = '--';
105
+ const COMMENT_CLOSE = '-->';
106
+
107
+ const TAG_OPEN = /[a-zA-Z]/;
108
+ const TAG_CHAR = /[a-zA-Z0-9]/;
109
+ const ATTRIBUTE_NAME = /[^\t\n\f />"'=]/;
110
+
111
+ const EXTERNAL = /\bexternal\b/;
112
+
113
+ const WHITESPACE = /[\s\n\r]/;
106
114
 
107
115
  /** @param {string} html */
108
- function clean_html(html) {
109
- return html
110
- .replace(/<!\[CDATA\[[\s\S]*?\]\]>/gm, '')
111
- .replace(/(<script[\s\S]*?>)[\s\S]*?<\/script>/gm, '$1</' + 'script>')
112
- .replace(/(<style[\s\S]*?>)[\s\S]*?<\/style>/gm, '$1</' + 'style>')
113
- .replace(/<!--[\s\S]*?-->/gm, '');
114
- }
116
+ function crawl(html) {
117
+ /** @type {string[]} */
118
+ const hrefs = [];
115
119
 
116
- /** @param {string} attrs */
117
- function get_href(attrs) {
118
- const match = /(?:[\s'"]|^)href\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs);
119
- return match && (match[1] || match[2] || match[3]);
120
- }
120
+ let i = 0;
121
+ main: while (i < html.length) {
122
+ const char = html[i];
121
123
 
122
- /** @param {string} attrs */
123
- function get_src(attrs) {
124
- const match = /(?:[\s'"]|^)src\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs);
125
- return match && (match[1] || match[2] || match[3]);
126
- }
124
+ if (char === '<') {
125
+ if (html[i + 1] === '!') {
126
+ i += 2;
127
127
 
128
- /** @param {string} attrs */
129
- function is_rel_external(attrs) {
130
- const match = /rel\s*=\s*(?:["'][^>]*(external)[^>]*["']|(external))/.exec(attrs);
131
- return !!match;
132
- }
128
+ if (html.substr(i, DOCTYPE.length).toUpperCase() === DOCTYPE) {
129
+ i += DOCTYPE.length;
130
+ while (i < html.length) {
131
+ if (html[i++] === '>') {
132
+ continue main;
133
+ }
134
+ }
135
+ }
136
+
137
+ // skip cdata
138
+ if (html.substr(i, CDATA_OPEN.length) === CDATA_OPEN) {
139
+ i += CDATA_OPEN.length;
140
+ while (i < html.length) {
141
+ if (html.substr(i, CDATA_CLOSE.length) === CDATA_CLOSE) {
142
+ i += CDATA_CLOSE.length;
143
+ continue main;
144
+ }
145
+
146
+ i += 1;
147
+ }
148
+ }
149
+
150
+ // skip comments
151
+ if (html.substr(i, COMMENT_OPEN.length) === COMMENT_OPEN) {
152
+ i += COMMENT_OPEN.length;
153
+ while (i < html.length) {
154
+ if (html.substr(i, COMMENT_CLOSE.length) === COMMENT_CLOSE) {
155
+ i += COMMENT_CLOSE.length;
156
+ continue main;
157
+ }
158
+
159
+ i += 1;
160
+ }
161
+ }
162
+ }
163
+
164
+ // parse opening tags
165
+ const start = ++i;
166
+ if (TAG_OPEN.test(html[start])) {
167
+ while (i < html.length) {
168
+ if (!TAG_CHAR.test(html[i])) {
169
+ break;
170
+ }
171
+
172
+ i += 1;
173
+ }
174
+
175
+ const tag = html.slice(start, i).toUpperCase();
176
+
177
+ if (tag === 'SCRIPT' || tag === 'STYLE') {
178
+ while (i < html.length) {
179
+ if (
180
+ html[i] === '<' &&
181
+ html[i + 1] === '/' &&
182
+ html.substr(i + 2, tag.length).toUpperCase() === tag
183
+ ) {
184
+ continue main;
185
+ }
186
+
187
+ i += 1;
188
+ }
189
+ }
190
+
191
+ let rel = '';
192
+ let href = '';
193
+
194
+ while (i < html.length) {
195
+ const start = i;
196
+
197
+ const char = html[start];
198
+ if (char === '>') break;
199
+
200
+ if (ATTRIBUTE_NAME.test(char)) {
201
+ i += 1;
202
+
203
+ while (i < html.length) {
204
+ if (!ATTRIBUTE_NAME.test(html[i])) {
205
+ break;
206
+ }
133
207
 
134
- /** @param {string} attrs */
135
- function get_srcset_urls(attrs) {
136
- const results = [];
137
- // Note that the srcset allows any ASCII whitespace, including newlines.
138
- const match = /([\s'"]|^)srcset\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/s.exec(attrs);
139
- if (match) {
140
- const attr_content = match[1] || match[2] || match[3];
141
- // Parse the content of the srcset attribute.
142
- // The regexp is modelled after the srcset specs (https://html.spec.whatwg.org/multipage/images.html#srcset-attribute)
143
- // and should cover most reasonable cases.
144
- const regex = /\s*([^\s,]\S+[^\s,])\s*((?:\d+w)|(?:-?\d+(?:\.\d+)?(?:[eE]-?\d+)?x))?/gm;
145
- let sub_matches;
146
- while ((sub_matches = regex.exec(attr_content))) {
147
- results.push(sub_matches[1]);
208
+ i += 1;
209
+ }
210
+
211
+ const name = html.slice(start, i).toLowerCase();
212
+
213
+ while (WHITESPACE.test(html[i])) i += 1;
214
+
215
+ if (html[i] === '=') {
216
+ i += 1;
217
+ while (WHITESPACE.test(html[i])) i += 1;
218
+
219
+ let value;
220
+
221
+ if (html[i] === "'" || html[i] === '"') {
222
+ const quote = html[i++];
223
+
224
+ const start = i;
225
+ let escaped = false;
226
+
227
+ while (i < html.length) {
228
+ if (!escaped) {
229
+ const char = html[i];
230
+
231
+ if (html[i] === quote) {
232
+ break;
233
+ }
234
+
235
+ if (char === '\\') {
236
+ escaped = true;
237
+ }
238
+ }
239
+
240
+ i += 1;
241
+ }
242
+
243
+ value = html.slice(start, i);
244
+ } else {
245
+ const start = i;
246
+ while (html[i] !== '>' && !WHITESPACE.test(html[i])) i += 1;
247
+ value = html.slice(start, i);
248
+
249
+ i -= 1;
250
+ }
251
+
252
+ if (name === 'rel') {
253
+ rel = value;
254
+ } else if (name === 'href') {
255
+ href = value;
256
+ } else if (name === 'src') {
257
+ hrefs.push(value);
258
+ } else if (name === 'srcset') {
259
+ const candidates = value.split(',');
260
+ for (const candidate of candidates) {
261
+ const src = candidate.trim().split(WHITESPACE)[0];
262
+ hrefs.push(src);
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ i += 1;
269
+ }
270
+
271
+ if (href && !EXTERNAL.test(rel)) {
272
+ hrefs.push(href);
273
+ }
274
+ }
148
275
  }
276
+
277
+ i += 1;
149
278
  }
150
- return results;
279
+
280
+ return hrefs;
151
281
  }
152
282
 
283
+ /**
284
+ * @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
285
+ * @typedef {import('types/config').PrerenderOnErrorValue} OnError
286
+ * @typedef {import('types/internal').Logger} Logger
287
+ */
288
+
153
289
  /** @type {(errorDetails: Parameters<PrerenderErrorHandler>[0] ) => string} */
154
290
  function errorDetailsToString({ status, path, referrer, referenceType }) {
155
291
  return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
@@ -357,36 +493,8 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
357
493
  });
358
494
 
359
495
  if (is_html && config.kit.prerender.crawl) {
360
- const cleaned = clean_html(/** @type {string} */ (rendered.body));
361
-
362
- let match;
363
- const pattern = /<(a|img|link|source)\s+([\s\S]+?)>/gm;
364
-
365
- const hrefs = [];
366
-
367
- while ((match = pattern.exec(cleaned))) {
368
- const element = match[1];
369
- const attrs = match[2];
370
-
371
- if (element === 'a' || element === 'link') {
372
- if (is_rel_external(attrs)) continue;
373
-
374
- let href = get_href(attrs);
375
- if (!href) continue;
376
-
377
- const i = href.indexOf('#');
378
- href = i < 0 ? href : href.substring(0, i);
379
- hrefs.push(href);
380
- } else {
381
- if (element === 'img') {
382
- hrefs.push(get_src(attrs));
383
- }
384
- hrefs.push(...get_srcset_urls(attrs));
385
- }
386
- }
387
-
388
- for (const href of hrefs) {
389
- if (!href) continue;
496
+ for (const href of crawl(/** @type {string} */ (rendered.body))) {
497
+ if (href.startsWith('data:')) continue;
390
498
 
391
499
  const resolved = resolve$1(path, href);
392
500
  if (!is_root_relative(resolved)) continue;
package/dist/cli.js CHANGED
@@ -479,6 +479,21 @@ const options = object(
479
479
 
480
480
  hydrate: boolean(true),
481
481
 
482
+ methodOverride: object({
483
+ parameter: string('_method'),
484
+ allowed: validate([], (input, keypath) => {
485
+ if (!Array.isArray(input) || !input.every((method) => typeof method === 'string')) {
486
+ throw new Error(`${keypath} must be an array of strings`);
487
+ }
488
+
489
+ if (input.map((i) => i.toUpperCase()).includes('GET')) {
490
+ throw new Error(`${keypath} cannot contain "GET"`);
491
+ }
492
+
493
+ return input;
494
+ })
495
+ }),
496
+
482
497
  package: object({
483
498
  dir: string('package'),
484
499
  // excludes all .d.ts and filename starting with _
@@ -575,7 +590,14 @@ const options = object(
575
590
  files: fun((filename) => !/\.DS_STORE/.test(filename))
576
591
  }),
577
592
 
578
- ssr: boolean(true),
593
+ // TODO remove this for 1.0
594
+ ssr: validate(null, (input) => {
595
+ if (input !== undefined) {
596
+ throw new Error(
597
+ 'config.kit.ssr has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'
598
+ );
599
+ }
600
+ }),
579
601
 
580
602
  target: string(null),
581
603
 
@@ -846,7 +868,7 @@ async function launch(port, https) {
846
868
  exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
847
869
  }
848
870
 
849
- const prog = sade('svelte-kit').version('1.0.0-next.220');
871
+ const prog = sade('svelte-kit').version('1.0.0-next.224');
850
872
 
851
873
  prog
852
874
  .command('dev')
@@ -998,7 +1020,7 @@ async function check_port(port) {
998
1020
  function welcome({ port, host, https, open, loose, allow, cwd }) {
999
1021
  if (open) launch(port, https);
1000
1022
 
1001
- console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.220'}\n`));
1023
+ console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.224'}\n`));
1002
1024
 
1003
1025
  const protocol = https ? 'https:' : 'http:';
1004
1026
  const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';