-
-
Notifications
You must be signed in to change notification settings - Fork 2k
/
Copy pathutils.js
200 lines (175 loc) · 6.15 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import * as fs from 'fs';
import * as path from 'path';
import { posixify, mkdirp, walk } from './filesystem.js';
/**
* Resolves the `$lib` alias.
*
* TODO: make this more generic to also handle other aliases the user could have defined via
* `kit.alias`. Also investigate how to do this in a more robust way (right now regex string
* replacement is used).
* For more discussion see https://github.com./sveltejs/kit/pull/2453
*
* @param {string} file Relative to the lib root
* @param {string} content
* @param {import('./types').ValidatedConfig} config
* @returns {string}
*/
export function resolve_lib_alias(file, content, config) {
const aliases = { $lib: path.resolve(config.package.source), ...(config.kit?.alias ?? {}) };
/**
* @param {string} match
* @param {string} _
* @param {string} import_path
*/
const replace_import_path = (match, _, import_path) => {
for (const [alias, value] of Object.entries(aliases)) {
if (!import_path.startsWith(alias)) continue;
const full_path = path.join(config.package.source, file);
const full_import_path = path.join(value, import_path.slice(alias.length));
let resolved = posixify(path.relative(path.dirname(full_path), full_import_path));
resolved = resolved.startsWith('.') ? resolved : './' + resolved;
return match.replace(import_path, resolved);
}
return match;
};
content = content.replace(/from\s+('|")([^"';,]+?)\1/g, replace_import_path);
content = content.replace(/import\s*\(\s*('|")([^"';,]+?)\1\s*\)/g, replace_import_path);
return content;
}
/**
* Strip out lang="X" or type="text/X" tags. Doing it here is only a temporary solution.
* See https://github.com./sveltejs/kit/issues/2450 for ideas for places where it's handled better.
*
* @param {string} content
*/
export function strip_lang_tags(content) {
return content
.replace(
/(<!--[^]*?-->)|(<script[^>]*?)\s(?:type|lang)=(["'])(.*?)\3/g,
// things like application/ld+json should be kept as-is. Preprocessed languages are "ts" etc
(match, s1, s2, _, s4) => (s4?.startsWith('application/') ? match : (s1 ?? '') + (s2 ?? ''))
)
.replace(/(<!--[^]*?-->)|(<style[^>]*?)\s(?:type|lang)=(["']).*?\3/g, '$1$2');
}
/**
* @param {string} file
* @param {Parameters<typeof fs.writeFileSync>[1]} contents
*/
export function write(file, contents) {
mkdirp(path.dirname(file));
fs.writeFileSync(file, contents);
}
/** @type {Map<string, string>} */
let current = new Map();
/**
* @param {string} file
* @param {string} contents
*/
export function write_if_changed(file, contents) {
if (current.get(file) !== contents) {
write(file, contents);
current.set(file, contents);
return true;
}
return false;
}
/**
* @param {import('./types').ValidatedConfig} config
* @returns {import('./types').File[]}
*/
export function scan(config) {
return walk(config.package.source).map((file) => analyze(config, file));
}
/**
* @param {import('./types').ValidatedConfig} config
* @param {string} file
* @returns {import('./types').File}
*/
export function analyze(config, file) {
const name = posixify(file);
const svelte_extension = config.extensions.find((ext) => name.endsWith(ext));
const base = svelte_extension ? name : name.slice(0, -path.extname(name).length);
const dest = svelte_extension
? name.slice(0, -svelte_extension.length) + '.svelte'
: name.endsWith('.d.ts')
? name
: name.endsWith('.ts')
? name.slice(0, -3) + '.js'
: name;
return {
name,
dest,
base,
is_included: config.package.files(name),
is_exported: config.package.exports(name),
is_svelte: !!svelte_extension
};
}
/**
* @param {string} cwd
* @param {NonNullable<import('types').PackageConfig['packageJson']>} packageJson
* @param {import('./types').File[]} files
*/
export function generate_pkg(cwd, packageJson, files) {
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
const original = JSON.parse(JSON.stringify(pkg));
// Remove fields that are specific to the original package.json
// See: https://pnpm.io/package_json#publishconfigdirectory
delete pkg.publishConfig?.directory;
delete pkg.linkDirectory?.directory;
delete pkg.scripts;
pkg.type = 'module';
pkg.exports = {
'./package.json': './package.json',
...pkg.exports
};
/** @type {Record<string, string>} */
const clashes = {};
for (const file of files) {
if (file.is_included && file.is_exported) {
const original = `$lib/${file.name}`;
const entry = `./${file.dest}`;
const key = entry.replace(/\/index\.js$|(\/[^/]+)\.js$/, '$1');
if (clashes[key]) {
throw new Error(
`Duplicate "${key}" export. Please remove or rename either ${clashes[key]} or ${original}`
);
}
if (!pkg.exports[key]) {
pkg.exports[key] = entry;
}
clashes[key] = original;
}
}
if (!pkg.dependencies?.svelte && !pkg.peerDependencies?.svelte) {
console.warn(
'Svelte libraries should include "svelte" in either "dependencies" or "peerDependencies".'
);
}
if (!pkg.svelte && files.some((file) => file.is_svelte)) {
// Several heuristics in Kit/vite-plugin-svelte to tell Vite to mark Svelte packages
// rely on the "svelte" property. Vite/Rollup/Webpack plugin can all deal with it.
// See https://github.com./sveltejs/kit/issues/1959 for more info and related threads.
if (pkg.exports['.']) {
const svelte_export =
typeof pkg.exports['.'] === 'string'
? pkg.exports['.']
: pkg.exports['.'].svelte || pkg.exports['.'].import || pkg.exports['.'].default;
if (svelte_export) {
pkg.svelte = svelte_export;
} else {
console.warn(
'Cannot generate a "svelte" entry point because the "." entry in "exports" is not a string. If you set it by hand, please also set one of the options as a "svelte" entry point in your package.json\n' +
'Example: { ..., "svelte": "./index.svelte" } }\n'
);
}
} else {
console.warn(
'Cannot generate a "svelte" entry point because the "." entry in "exports" is missing. Please specify one or set a "svelte" entry point yourself in your package.json\n' +
'Example: { ..., "svelte": "./index.svelte" } }\n'
);
}
}
const final = packageJson(original, pkg);
return { pkg: packageJson(original, pkg), pkg_name: final?.name ?? original.name };
}