@sveltejs/kit 3.0.0-next.14 → 3.0.0-next.16

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.
Files changed (56) hide show
  1. package/package.json +6 -3
  2. package/src/cli.js +6 -3
  3. package/src/core/adapt/builder.js +12 -5
  4. package/src/core/config/index.js +4 -5
  5. package/src/core/env.js +3 -3
  6. package/src/core/postbuild/prerender.js +6 -10
  7. package/src/core/sync/sync.js +3 -2
  8. package/src/core/sync/utils.js +2 -2
  9. package/src/core/sync/write_tsconfig/index.js +71 -53
  10. package/src/core/sync/write_tsconfig/utils.js +0 -61
  11. package/src/core/sync/write_tsconfig/validate.js +128 -0
  12. package/src/core/sync/write_types/index.js +2 -2
  13. package/src/exports/public.d.ts +22 -16
  14. package/src/exports/vite/build/build_server.js +2 -3
  15. package/src/exports/vite/dev/index.js +44 -36
  16. package/src/exports/vite/index.js +46 -5
  17. package/src/exports/vite/utils.js +61 -8
  18. package/src/runner.js +4 -2
  19. package/src/runtime/app/forms.js +4 -7
  20. package/src/runtime/app/internal/transport.js +53 -0
  21. package/src/runtime/app/paths/client.js +2 -2
  22. package/src/runtime/app/paths/internal/client.js +2 -2
  23. package/src/runtime/app/server/remote/prerender.js +6 -10
  24. package/src/runtime/app/server/remote/query.js +3 -3
  25. package/src/runtime/app/server/remote/requested.js +2 -2
  26. package/src/runtime/app/server/remote/shared.js +1 -16
  27. package/src/runtime/client/client.js +29 -25
  28. package/src/runtime/client/parse.js +1 -1
  29. package/src/runtime/client/remote-functions/command.svelte.js +1 -2
  30. package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
  31. package/src/runtime/client/remote-functions/query/proxy.js +2 -2
  32. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -2
  33. package/src/runtime/pathname.js +7 -1
  34. package/src/runtime/server/data/index.js +5 -8
  35. package/src/runtime/server/dev.js +22 -0
  36. package/src/runtime/server/endpoint.js +3 -4
  37. package/src/runtime/server/fetch.js +22 -24
  38. package/src/runtime/server/index.js +54 -22
  39. package/src/runtime/server/internal.js +12 -5
  40. package/src/runtime/server/page/actions.js +18 -43
  41. package/src/runtime/server/page/data_serializer.js +12 -13
  42. package/src/runtime/server/page/index.js +16 -32
  43. package/src/runtime/server/page/load_data.js +26 -15
  44. package/src/runtime/server/page/render.js +9 -11
  45. package/src/runtime/server/page/respond_with_error.js +8 -20
  46. package/src/runtime/server/remote-functions.js +11 -15
  47. package/src/runtime/server/respond.js +26 -31
  48. package/src/runtime/server/state.js +36 -19
  49. package/src/runtime/server/utils.js +0 -20
  50. package/src/runtime/shared.js +16 -38
  51. package/src/types/internal.d.ts +45 -52
  52. package/src/utils/filesystem.js +1 -23
  53. package/src/version.js +1 -1
  54. package/types/index.d.ts +24 -18
  55. package/types/index.d.ts.map +1 -1
  56. package/src/runtime/server/app.js +0 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "3.0.0-next.14",
3
+ "version": "3.0.0-next.16",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -30,12 +30,12 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@opentelemetry/api": "^1.9.0",
33
- "@playwright/test": "~1.61.0",
33
+ "@playwright/test": "^1.62.0",
34
34
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
35
35
  "@types/connect": "^3.4.38",
36
36
  "@types/node": "^22.19.19",
37
37
  "dts-buddy": "^0.8.3",
38
- "jsdom": "^29.1.1",
38
+ "jsdom": "^30.0.0",
39
39
  "rolldown": "^1.2.0",
40
40
  "svelte": "^5.56.3",
41
41
  "svelte-preprocess": "^6.0.5",
@@ -71,6 +71,9 @@
71
71
  "svelte-kit.js"
72
72
  ],
73
73
  "imports": {
74
+ "#app/internal/transport": {
75
+ "default": "./src/runtime/app/internal/transport.js"
76
+ },
74
77
  "#app/paths": {
75
78
  "workerd": "./src/runtime/app/paths/server.js",
76
79
  "browser": "./src/runtime/app/paths/client.js",
package/src/cli.js CHANGED
@@ -2,8 +2,9 @@ import fs from 'node:fs';
2
2
  import process from 'node:process';
3
3
  import { parseArgs, styleText } from 'node:util';
4
4
  import { extract_svelte_config, load_vite_config } from './core/config/index.js';
5
- import { coalesce_to_error } from './utils/error.js';
6
5
  import { resolve_explicit_env_entry } from './core/env.js';
6
+ import { coalesce_to_error } from './utils/error.js';
7
+ import { import_peer } from './utils/import.js';
7
8
 
8
9
  /** @param {unknown} e */
9
10
  function handle_error(e) {
@@ -96,14 +97,16 @@ if (command === 'sync') {
96
97
  }
97
98
 
98
99
  try {
99
- const vite_config = await load_vite_config(values.config);
100
+ const vite = /** @type {import('vite')} */ (await import_peer('vite', process.cwd()));
101
+
102
+ const vite_config = await load_vite_config(values.config, vite);
100
103
  const sveltekit_config = extract_svelte_config(vite_config);
101
104
 
102
105
  const sync = await import('./core/sync/sync.js');
103
106
  sync.all_types(sveltekit_config, vite_config.root);
104
107
 
105
108
  const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config.kit);
106
- await sync.env(sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
109
+ await sync.env(vite, sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
107
110
  } catch (error) {
108
111
  handle_error(error);
109
112
  } finally {
@@ -5,12 +5,19 @@
5
5
  /** @import { RouteData, ValidatedConfig, BuildData, ServerMetadata, ServerMetadataRoute, Prerendered, PrerenderMap, Logger, RemoteChunk } from 'types' */
6
6
  import { loadEnv } from 'vite';
7
7
  import * as devalue from 'devalue';
8
- import { createReadStream, createWriteStream, existsSync, statSync } from 'node:fs';
8
+ import {
9
+ createReadStream,
10
+ createWriteStream,
11
+ existsSync,
12
+ mkdirSync,
13
+ rmSync,
14
+ statSync
15
+ } from 'node:fs';
9
16
  import { extname, resolve, join, dirname, relative } from 'node:path';
10
17
  import { pipeline } from 'node:stream';
11
18
  import { promisify } from 'node:util';
12
19
  import zlib from 'node:zlib';
13
- import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
20
+ import { copy } from '../../utils/filesystem.js';
14
21
  import { posixify } from '../../utils/os.js';
15
22
  import { generate_manifest } from '../generate_manifest/index.js';
16
23
  import { get_route_segments } from '../../utils/routing.js';
@@ -99,8 +106,8 @@ export function create_builder({
99
106
 
100
107
  return {
101
108
  log,
102
- rimraf,
103
- mkdirp,
109
+ rimraf: (dir) => rmSync(dir, { force: true, recursive: true }),
110
+ mkdirp: (dir) => mkdirSync(dir, { recursive: true }),
104
111
  copy,
105
112
 
106
113
  config,
@@ -271,7 +278,7 @@ export function create_builder({
271
278
  exports: module.exports
272
279
  });
273
280
 
274
- rimraf(entrypoint);
281
+ rmSync(entrypoint, { force: true, recursive: true });
275
282
  write(entrypoint, facade);
276
283
  }
277
284
  };
@@ -120,13 +120,12 @@ export function load_error_page(config) {
120
120
 
121
121
  /**
122
122
  * @param {string} [config]
123
+ * @param {typeof import('vite')} [vite]
123
124
  */
124
- export async function load_vite_config(config) {
125
- const { resolveConfig } = /** @type {import('vite')} */ (
126
- await import_peer('vite', process.cwd())
127
- );
125
+ export async function load_vite_config(config, vite) {
126
+ vite ??= /** @type {import('vite')} */ (await import_peer('vite', process.cwd()));
128
127
 
129
- return resolveConfig({ configFile: config }, 'build', process.env.MODE ?? 'production');
128
+ return vite.resolveConfig({ configFile: config }, 'build', process.env.MODE ?? 'production');
130
129
  }
131
130
 
132
131
  /**
package/src/core/env.js CHANGED
@@ -2,7 +2,6 @@
2
2
  /** @import { EnvVarConfig } from '@sveltejs/kit' */
3
3
  /** @import { ValidatedKitConfig } from 'types' */
4
4
  import path from 'node:path';
5
- import * as vite from 'vite';
6
5
  import * as devalue from 'devalue';
7
6
  import { GENERATED_COMMENT } from '../constants.js';
8
7
  import { dedent } from './sync/utils.js';
@@ -25,13 +24,14 @@ export function resolve_explicit_env_entry(config) {
25
24
  }
26
25
 
27
26
  /**
27
+ * @param {typeof import('vite')} vite
28
28
  * @param {ValidatedKitConfig} kit
29
29
  * @param {string | null} file
30
30
  * @param {string} root
31
31
  * @param {string} mode
32
32
  * @returns {Promise<Record<string, EnvVarConfig<any>> | null>}
33
33
  */
34
- export async function load_explicit_env(kit, file, root, mode) {
34
+ export async function load_explicit_env(vite, kit, file, root, mode) {
35
35
  if (!file) return null;
36
36
 
37
37
  const server = await vite.createServer({
@@ -53,7 +53,7 @@ export async function load_explicit_env(kit, file, root, mode) {
53
53
  /** @type {Record<string, EnvVarConfig<any>>} */
54
54
  let variables;
55
55
 
56
- const runner = get_runner(server);
56
+ const runner = get_runner(vite, server);
57
57
 
58
58
  /** @type {import('../runtime/app/env/internal.js')} */ (
59
59
  await runner.import(`${runtime_directory}/app/env/internal.js`)
@@ -1,7 +1,7 @@
1
- import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
- import { mkdirp, walk } from '../../utils/filesystem.js';
4
+ import { walk } from '../../utils/filesystem.js';
5
5
  import { posixify } from '../../utils/os.js';
6
6
  import { noop } from '../../utils/functions.js';
7
7
  import { decode_uri, is_root_relative, resolve } from '../../utils/url.js';
@@ -157,7 +157,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
157
157
  const file = output_filename('/', true);
158
158
  const dest = `${config.outDir}/output/prerendered/pages/${file}`;
159
159
 
160
- mkdirp(dirname(dest));
160
+ mkdirSync(dirname(dest), { recursive: true });
161
161
  writeFileSync(dest, fallback);
162
162
 
163
163
  prerendered.pages.set('/', { file });
@@ -480,7 +480,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
480
480
  }
481
481
 
482
482
  if (!headers['x-sveltekit-normalize']) {
483
- mkdirp(dirname(dest));
483
+ mkdirSync(dirname(dest), { recursive: true });
484
484
 
485
485
  writeFileSync(
486
486
  dest,
@@ -526,7 +526,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
526
526
  );
527
527
  }
528
528
 
529
- mkdirp(dir);
529
+ mkdirSync(dir, { recursive: true });
530
530
 
531
531
  writeFileSync(dest, body);
532
532
  written.add(file);
@@ -629,14 +629,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
629
629
  }
630
630
  }
631
631
 
632
- const transport = (await internal.get_hooks()).transport ?? {};
633
632
  for (const internals of prerender_functions) {
634
633
  if (internals.has_arg) {
635
634
  for (const arg of (await internals.inputs?.()) ?? []) {
636
- void enqueue(
637
- null,
638
- remote_prefix + internals.id + '/' + stringify_remote_arg(arg, transport)
639
- );
635
+ void enqueue(null, remote_prefix + internals.id + '/' + stringify_remote_arg(arg));
640
636
  }
641
637
  } else {
642
638
  void enqueue(null, remote_prefix + internals.id);
@@ -89,13 +89,14 @@ export function all_types(config, root) {
89
89
 
90
90
  /**
91
91
  * Generate modules and types for explicit env vars
92
+ * @param {typeof import('vite')} vite
92
93
  * @param {import('types').ValidatedKitConfig} kit
93
94
  * @param {string | null} entry
94
95
  * @param {string} root The Vite root
95
96
  * @param {string} mode The Vite mode
96
97
  */
97
- export async function env(kit, entry, root, mode) {
98
- const env_config = await load_explicit_env(kit, entry, root, mode);
98
+ export async function env(vite, kit, entry, root, mode) {
99
+ const env_config = await load_explicit_env(vite, kit, entry, root, mode);
99
100
 
100
101
  write_env(entry, env_config, root);
101
102
 
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { styleText } from 'node:util';
4
- import { mkdirp, resolve_entry } from '../../utils/filesystem.js';
4
+ import { resolve_entry } from '../../utils/filesystem.js';
5
5
 
6
6
  /** @type {Map<string, string>} */
7
7
  const previous_contents = new Map();
@@ -22,7 +22,7 @@ export function write_if_changed(file, code) {
22
22
  */
23
23
  export function write(file, code) {
24
24
  previous_contents.set(file, code);
25
- mkdirp(path.dirname(file));
25
+ fs.mkdirSync(path.dirname(file), { recursive: true });
26
26
  fs.writeFileSync(file, code);
27
27
  }
28
28
 
@@ -6,13 +6,12 @@ import { styleText } from 'node:util';
6
6
  import { write_if_changed } from '../utils.js';
7
7
  import {
8
8
  ESSENTIAL_OPTIONS,
9
- extends_id,
10
9
  get_subpath_imports,
11
10
  normalize_config,
12
11
  RECOMMENDED_OPTIONS,
13
- remove_trailing_slashstar,
14
- validate_resolved_config
12
+ remove_trailing_slashstar
15
13
  } from './utils.js';
14
+ import { extends_id, validate_resolved_config } from './validate.js';
16
15
 
17
16
  /** @type {import('typescript')} */
18
17
  let ts;
@@ -29,16 +28,16 @@ try {
29
28
  */
30
29
  export function write_tsconfig(kit, root) {
31
30
  const paths = get_paths(kit, root);
31
+ const types = ['$app/types'];
32
32
 
33
33
  write_parent_tsconfig(
34
- root,
35
34
  root,
36
35
  '$app/tsconfig',
37
36
  {
38
37
  compilerOptions: {
39
38
  paths,
40
39
  rootDirs: ['.', `${kit.outDir}/types`],
41
- types: ['$app/types'],
40
+ types,
42
41
 
43
42
  // This is required for svelte-package to work as expected
44
43
  // Can be overwritten
@@ -46,45 +45,48 @@ export function write_tsconfig(kit, root) {
46
45
 
47
46
  ...ESSENTIAL_OPTIONS,
48
47
  ...RECOMMENDED_OPTIONS
49
- },
50
- exclude: [kit.files.serviceWorker]
51
- },
52
- {
53
- extends: '$app/tsconfig',
54
- include: ['src']
48
+ }
55
49
  },
56
50
  kit.typescript.config
57
51
  );
58
52
 
59
- write_parent_tsconfig(
60
- root,
61
- kit.files.serviceWorker,
62
- '$app/tsconfig/service-worker',
63
- {
64
- compilerOptions: {
65
- paths,
66
- types: ['$app/types'],
67
- lib: ['ESNext', 'WebWorker'],
68
- ...ESSENTIAL_OPTIONS
69
- }
70
- },
71
- {
53
+ validate_config(root, {
54
+ paths,
55
+ types,
56
+ exclusions: [kit.files.serviceWorker],
57
+ example: {
58
+ extends: '$app/tsconfig'
59
+ }
60
+ });
61
+
62
+ write_parent_tsconfig(root, '$app/tsconfig/service-worker', {
63
+ compilerOptions: {
64
+ paths,
65
+ types,
66
+ lib: ['ESNext', 'WebWorker'],
67
+ ...ESSENTIAL_OPTIONS,
68
+ ...RECOMMENDED_OPTIONS
69
+ }
70
+ });
71
+
72
+ validate_config(kit.files.serviceWorker, {
73
+ paths,
74
+ types,
75
+ example: {
72
76
  extends: '$app/tsconfig/service-worker'
73
77
  }
74
- );
78
+ });
75
79
  }
76
80
 
77
81
  /**
78
82
  * Write a generated `tsconfig.json` inside `node_modules`, for the
79
83
  * user config to extend
80
84
  * @param {string} root The project root
81
- * @param {string} dir The directory to resolve a user config from
82
85
  * @param {string} id The id of the generated config
83
86
  * @param {any} config The contents of the generated tsconfig, with paths relative to `root`
84
- * @param {any} example What to print if the user config does _not_ extend the generated config
85
87
  * @param {ValidatedKitConfig['typescript']['config']} [transform] TODO get rid of this
86
88
  */
87
- function write_parent_tsconfig(root, dir, id, config, example, transform) {
89
+ function write_parent_tsconfig(root, id, config, transform) {
88
90
  // simplified tsconfig resolvers (e.g. Playwright's) only find `${id}.json`, not `${id}/tsconfig.json`
89
91
  const out_file = path.join(root, `node_modules/${id}.json`);
90
92
 
@@ -92,44 +94,60 @@ function write_parent_tsconfig(root, dir, id, config, example, transform) {
92
94
  normalized = transform?.(normalized) ?? normalized;
93
95
 
94
96
  write_if_changed(out_file, JSON.stringify(normalized, null, '\t'));
97
+ }
95
98
 
99
+ /**
100
+ * @param {string} dir The directory to resolve a user config from
101
+ * @param {Object} options
102
+ * @param {Record<string, string[]>} options.paths The expected paths
103
+ * @param {string[]} options.types The expected types
104
+ * @param {string[]} [options.exclusions] Files that should be excluded
105
+ * @param {any} options.example What to print if the user config does _not_ extend the generated config
106
+ */
107
+ function validate_config(dir, options) {
96
108
  if (!ts) {
97
109
  // The user has not installed TypeScript. Skip validation of config.
98
110
  return;
99
111
  }
100
112
 
101
113
  const user_config = load_user_tsconfig(dir);
114
+ if (!user_config || !modified_since_last_check(user_config.file)) return;
102
115
 
103
- if (user_config && modified_since_last_check(user_config.file)) {
104
- // now that we've written the parent config, we can resolve the
105
- // user config and validate that nothing important was overwritten
106
- if (!extends_id(user_config.options, id)) {
107
- console.warn(
108
- styleText(
109
- ['bold', 'yellow'],
110
- `${path.relative(process.cwd(), user_config.file)} should extend SvelteKit's built-in configuration:`
111
- )
112
- );
116
+ // now that we've written the parent config, we can resolve the
117
+ // user config and validate that nothing important was overwritten
118
+ if (!extends_id(user_config.options, options.example.extends)) {
119
+ console.warn(
120
+ styleText(
121
+ ['bold', 'yellow'],
122
+ `${path.relative(process.cwd(), user_config.file)} should extend SvelteKit's built-in configuration:`
123
+ )
124
+ );
113
125
 
114
- console.warn(JSON.stringify(example, null, ' '));
126
+ console.warn(JSON.stringify(options.example, null, ' '));
115
127
 
116
- return;
117
- }
128
+ return;
129
+ }
118
130
 
119
- const resolved = ts.parseJsonConfigFileContent(user_config.options, ts.sys, dir).options;
120
- const warnings = validate_resolved_config(resolved, config.compilerOptions);
131
+ const resolved = ts.parseJsonConfigFileContent(user_config.options, ts.sys, dir);
121
132
 
122
- if (warnings.length > 0) {
123
- console.warn(
124
- styleText(
125
- ['bold', 'yellow'],
126
- `Found issues while validating ${path.relative(process.cwd(), user_config.file)}`
127
- )
128
- );
133
+ const warnings = validate_resolved_config(
134
+ dir,
135
+ resolved,
136
+ options.paths,
137
+ options.types,
138
+ options.exclusions
139
+ );
129
140
 
130
- for (const warning of warnings) {
131
- console.warn(` - ${warning}`);
132
- }
141
+ if (warnings.length > 0) {
142
+ console.warn(
143
+ styleText(
144
+ ['bold', 'yellow'],
145
+ `Found issues while validating ${path.relative(process.cwd(), user_config.file)}`
146
+ )
147
+ );
148
+
149
+ for (const warning of warnings) {
150
+ console.warn(` - ${warning}`);
133
151
  }
134
152
  }
135
153
  }
@@ -36,16 +36,6 @@ export const RECOMMENDED_OPTIONS = {
36
36
  noEmit: true // prevent tsconfig error "overwriting input files" - Vite handles the build and ignores this
37
37
  };
38
38
 
39
- /**
40
- * Validates that a tsconfig contains `"extends": "<id>"`
41
- * @param {any} options
42
- * @param {string} id
43
- */
44
- export function extends_id(options, id) {
45
- const o = options.extends;
46
- return Array.isArray(o) ? o.includes(id) : o === id;
47
- }
48
-
49
39
  /**
50
40
  * Makes paths relative to the output file
51
41
  * @param {string} out
@@ -76,57 +66,6 @@ export function normalize_config(out, config, transform) {
76
66
  return transform?.(normalized) ?? normalized;
77
67
  }
78
68
 
79
- /**
80
- * @param {any} resolved
81
- * @param {any} options
82
- */
83
- export function validate_resolved_config(resolved, options) {
84
- const warnings = [];
85
-
86
- const join = (/** @type {string[]} */ array) =>
87
- array
88
- .map((v) => JSON.stringify(v))
89
- .join(', ')
90
- .replace(/, ([^,]*)$/, ' and $1');
91
-
92
- const missing_types = options.types?.filter(
93
- (/** @type {string} */ type) => !resolved.types?.includes(type)
94
- );
95
-
96
- if (missing_types.length > 0) {
97
- warnings.push(`"types" was overwritten. It must include ${join(missing_types)}`);
98
- }
99
-
100
- if (options.paths) {
101
- /** @type {Set<string>} */
102
- const mismatch = new Set();
103
-
104
- for (const [k, expected] of Object.entries(options.paths)) {
105
- const actual = resolved.paths?.[k]?.map((/** @type {string} */ x) =>
106
- path.resolve(/** @type {string} */ (resolved.pathsBasePath), x)
107
- );
108
-
109
- if (JSON.stringify(expected) !== JSON.stringify(actual)) {
110
- mismatch.add(remove_trailing_slashstar(k));
111
- }
112
- }
113
-
114
- if (mismatch.size > 0) {
115
- const joined = join([...mismatch]);
116
-
117
- warnings.push(`"paths" was overwritten. Imports from ${joined} may not typecheck`);
118
- }
119
- }
120
-
121
- for (const key in ESSENTIAL_OPTIONS) {
122
- if (resolved[key] !== options[key]) {
123
- warnings.push(`"${key}" was overwritten. It should be ${JSON.stringify(options[key])}`);
124
- }
125
- }
126
-
127
- return warnings;
128
- }
129
-
130
69
  /**
131
70
  * @param {string} file
132
71
  */
@@ -0,0 +1,128 @@
1
+ /** @import ts from 'typescript' */
2
+ import path from 'node:path';
3
+ import { ESSENTIAL_OPTIONS, remove_trailing_slashstar } from './utils.js';
4
+ import { posixify } from '../../../utils/os.js';
5
+
6
+ const formatter = new Intl.ListFormat('en-gb', { type: 'conjunction' });
7
+
8
+ /**
9
+ * @param {string[]} things
10
+ */
11
+ function join(things) {
12
+ return formatter.format(things.map((thing) => JSON.stringify(thing)));
13
+ }
14
+
15
+ /**
16
+ * @param {string} dir
17
+ * @param {ts.ParsedCommandLine} resolved
18
+ * @param {Record<string, string[]>} paths
19
+ * @param {string[]} types
20
+ * @param {string[]} [exclusions]
21
+ */
22
+ export function validate_resolved_config(dir, resolved, paths, types, exclusions) {
23
+ /** @type {string[]} */
24
+ const warnings = [];
25
+
26
+ if (resolved.options.types) {
27
+ validate_types(warnings, types, resolved.options.types);
28
+ }
29
+
30
+ if (resolved.options.paths) {
31
+ validate_paths(
32
+ warnings,
33
+ /** @type {string} */ (resolved.options.pathsBasePath),
34
+ paths,
35
+ resolved.options.paths
36
+ );
37
+ }
38
+
39
+ if (exclusions) {
40
+ validate_exclusions(warnings, dir, exclusions, resolved.fileNames);
41
+ }
42
+
43
+ for (const key in ESSENTIAL_OPTIONS) {
44
+ if (resolved.options[key] !== ESSENTIAL_OPTIONS[key]) {
45
+ warnings.push(
46
+ `"${key}" was overwritten. It should be ${JSON.stringify(ESSENTIAL_OPTIONS[key])}`
47
+ );
48
+ }
49
+ }
50
+
51
+ return warnings;
52
+ }
53
+
54
+ /**
55
+ * @param {string[]} warnings
56
+ * @param {string[]} expected
57
+ * @param {string[]} actual
58
+ */
59
+ export function validate_types(warnings, expected, actual) {
60
+ const missing_types = expected.filter((/** @type {string} */ type) => !actual.includes(type));
61
+
62
+ if (missing_types.length > 0) {
63
+ warnings.push(`"types" was overwritten. It must include ${join(missing_types)}`);
64
+ }
65
+
66
+ return warnings;
67
+ }
68
+
69
+ /**
70
+ * @param {string[]} warnings
71
+ * @param {string} base
72
+ * @param {Record<string, string[]>} expected
73
+ * @param {ts.MapLike<string[]>} actual
74
+ */
75
+ export function validate_paths(warnings, base, expected, actual) {
76
+ /** @type {Set<string>} */
77
+ const mismatch = new Set();
78
+
79
+ for (const [k, e] of Object.entries(expected)) {
80
+ const a = actual[k]?.map((/** @type {string} */ x) =>
81
+ path.resolve(/** @type {string} */ (base), x)
82
+ );
83
+
84
+ if (JSON.stringify(e) !== JSON.stringify(a)) {
85
+ mismatch.add(remove_trailing_slashstar(k));
86
+ }
87
+ }
88
+
89
+ if (mismatch.size > 0) {
90
+ const joined = join([...mismatch]);
91
+
92
+ warnings.push(`"paths" was overwritten. Imports from ${joined} may not typecheck`);
93
+ }
94
+
95
+ return warnings;
96
+ }
97
+
98
+ /**
99
+ * @param {string[]} warnings
100
+ * @param {string} dir
101
+ * @param {string[]} exclusions
102
+ * @param {string[]} files
103
+ */
104
+ export function validate_exclusions(warnings, dir, exclusions, files) {
105
+ const missing_exclusions = exclusions.map(posixify).filter((exclusion) => {
106
+ return files.some(
107
+ (f) => f === exclusion || f.startsWith(exclusion + '/') || f.startsWith(exclusion + '.')
108
+ );
109
+ });
110
+
111
+ if (missing_exclusions.length > 0) {
112
+ warnings.push(
113
+ `${join(missing_exclusions.map((file) => posixify(path.relative(dir, file))))} should be added to the "exclude" array`
114
+ );
115
+ }
116
+
117
+ return warnings;
118
+ }
119
+
120
+ /**
121
+ * Validates that a tsconfig contains `"extends": "<id>"`
122
+ * @param {any} options
123
+ * @param {string} id
124
+ */
125
+ export function extends_id(options, id) {
126
+ const o = options.extends;
127
+ return Array.isArray(o) ? o.includes(id) : o === id;
128
+ }
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import MagicString from 'magic-string';
4
- import { rimraf, walk, resolve_entry } from '../../../utils/filesystem.js';
4
+ import { walk, resolve_entry } from '../../../utils/filesystem.js';
5
5
  import { compact } from '../../../utils/array.js';
6
6
  import { posixify } from '../../../utils/os.js';
7
7
  import { ts } from '../ts.js';
@@ -49,7 +49,7 @@ export function write_all_types(config, manifest_data, root) {
49
49
  for (const file of walk(types_dir)) {
50
50
  const dir = path.dirname(file);
51
51
  if (!expected_directories.has(dir)) {
52
- rimraf(path.join(types_dir, file));
52
+ fs.rmSync(path.join(types_dir, file), { force: true, recursive: true });
53
53
  }
54
54
  }
55
55
  }