longmo-unplugin-info 1.0.0

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +508 -0
  3. package/client.d.ts +106 -0
  4. package/dist/astro.cjs +25 -0
  5. package/dist/astro.d.cts +11 -0
  6. package/dist/astro.d.mts +11 -0
  7. package/dist/astro.d.ts +11 -0
  8. package/dist/astro.mjs +23 -0
  9. package/dist/esbuild.cjs +16 -0
  10. package/dist/esbuild.d.cts +7 -0
  11. package/dist/esbuild.d.mts +7 -0
  12. package/dist/esbuild.d.ts +7 -0
  13. package/dist/esbuild.mjs +14 -0
  14. package/dist/index.cjs +16 -0
  15. package/dist/index.d.cts +7 -0
  16. package/dist/index.d.mts +7 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.mjs +10 -0
  19. package/dist/nuxt.cjs +43 -0
  20. package/dist/nuxt.d.cts +16 -0
  21. package/dist/nuxt.d.mts +16 -0
  22. package/dist/nuxt.d.ts +16 -0
  23. package/dist/nuxt.mjs +41 -0
  24. package/dist/rollup.cjs +16 -0
  25. package/dist/rollup.d.cts +7 -0
  26. package/dist/rollup.d.mts +7 -0
  27. package/dist/rollup.d.ts +7 -0
  28. package/dist/rollup.mjs +14 -0
  29. package/dist/rspack.cjs +16 -0
  30. package/dist/rspack.d.cts +7 -0
  31. package/dist/rspack.d.mts +7 -0
  32. package/dist/rspack.d.ts +7 -0
  33. package/dist/rspack.mjs +14 -0
  34. package/dist/shared/longmo-unplugin-info.B4uHFilH.mjs +609 -0
  35. package/dist/shared/longmo-unplugin-info.D5mpeSYM.cjs +619 -0
  36. package/dist/shared/longmo-unplugin-info.zS6I--Tu.d.cts +69 -0
  37. package/dist/shared/longmo-unplugin-info.zS6I--Tu.d.mts +69 -0
  38. package/dist/shared/longmo-unplugin-info.zS6I--Tu.d.ts +69 -0
  39. package/dist/vite.cjs +16 -0
  40. package/dist/vite.d.cts +7 -0
  41. package/dist/vite.d.mts +7 -0
  42. package/dist/vite.d.ts +7 -0
  43. package/dist/vite.mjs +14 -0
  44. package/dist/webpack.cjs +16 -0
  45. package/dist/webpack.d.cts +7 -0
  46. package/dist/webpack.d.mts +7 -0
  47. package/dist/webpack.d.ts +7 -0
  48. package/dist/webpack.mjs +14 -0
  49. package/package.json +168 -0
@@ -0,0 +1,609 @@
1
+ import path from 'node:path';
2
+ import process$1 from 'node:process';
3
+ import { createUnplugin } from 'unplugin';
4
+ import ci from 'ci-info';
5
+ import { simpleGit } from 'simple-git';
6
+ import parseGitUrl from 'git-url-parse';
7
+ import { exec } from 'node:child_process';
8
+ import { promisify } from 'node:util';
9
+ import fs from 'node:fs';
10
+
11
+ class BuildInfoModule {
12
+ name;
13
+ root;
14
+ options;
15
+ constructor(name, root, options) {
16
+ this.name = `${options?.prefix ?? "~build"}/${name}`;
17
+ this.root = root;
18
+ this.options = options;
19
+ }
20
+ buildStart(ctx) {
21
+ }
22
+ buildEnd(ctx) {
23
+ }
24
+ }
25
+
26
+ class BuildTimeModule extends BuildInfoModule {
27
+ now;
28
+ constructor(root, options) {
29
+ super("time", root, options);
30
+ }
31
+ buildStart() {
32
+ this.now = this.options.time ? this.options.time : /* @__PURE__ */ new Date();
33
+ }
34
+ load() {
35
+ return `const time = new Date(${this.now.getTime()})
36
+ export default time`;
37
+ }
38
+ }
39
+
40
+ async function getRepoInfo(root, extra = {}) {
41
+ const git = simpleGit(root);
42
+ if (!await git.checkIsRepo()) {
43
+ return void 0;
44
+ }
45
+ const [branch, currentCommit, committer, describe, tags, github, result] = await Promise.all([
46
+ getBranch(git),
47
+ getCommit(git),
48
+ getCommitter(git),
49
+ getDescribe(git),
50
+ getTags(git),
51
+ getGitHubUrl(git),
52
+ Promise.all(
53
+ Object.entries(extra).map(async ([key, fn]) => {
54
+ return [key, await fn(git)];
55
+ })
56
+ )
57
+ ]);
58
+ return {
59
+ ...branch,
60
+ ...currentCommit,
61
+ ...committer,
62
+ ...describe,
63
+ ...tags,
64
+ ...github,
65
+ ...Object.fromEntries(result)
66
+ };
67
+ }
68
+ async function getBranch(git) {
69
+ try {
70
+ const branch = (await git.branch([])).current;
71
+ return { branch };
72
+ } catch (error) {
73
+ return { branch: void 0 };
74
+ }
75
+ }
76
+ async function getCommit(git) {
77
+ try {
78
+ const log = await git.log(["-1"]);
79
+ const sha = log.latest?.hash;
80
+ const commitMessage = log.latest?.message;
81
+ const author = log.latest?.author_name;
82
+ const authorEmail = log.latest?.author_email;
83
+ const authorDate = log.latest?.date;
84
+ return {
85
+ sha,
86
+ abbreviatedSha: sha?.slice(0, 10),
87
+ commitMessage,
88
+ author,
89
+ authorEmail,
90
+ authorDate
91
+ };
92
+ } catch (error) {
93
+ return {
94
+ sha: void 0,
95
+ abbreviatedSha: void 0,
96
+ commitMessage: void 0,
97
+ author: void 0,
98
+ authorEmail: void 0,
99
+ authorDate: void 0
100
+ };
101
+ }
102
+ }
103
+ function removeLineBreak(str) {
104
+ return str.replace(/[\s\r\n]+$/, "");
105
+ }
106
+ async function getCommitter(git) {
107
+ try {
108
+ const [committer, committerEmail, committerDate] = await Promise.all([
109
+ git.show(["-s", "--format=%cn"]),
110
+ git.show(["-s", "--format=%ce"]),
111
+ git.show(["-s", "--format=%cd"])
112
+ ]);
113
+ return {
114
+ committer: removeLineBreak(committer),
115
+ committerEmail: removeLineBreak(committerEmail),
116
+ committerDate: removeLineBreak(committerDate)
117
+ };
118
+ } catch (error) {
119
+ return {
120
+ committer: void 0,
121
+ committerEmail: void 0,
122
+ committerDate: void 0
123
+ };
124
+ }
125
+ }
126
+ async function getTags(git) {
127
+ try {
128
+ const hash = await git.revparse(["HEAD"]);
129
+ const tags = await git.tags(["--points-at", hash]);
130
+ const all = await git.tags();
131
+ return { tag: tags.all[tags.all.length - 1], tags: tags.all, lastTag: all.latest };
132
+ } catch (error) {
133
+ return { tags: void 0, lastTag: void 0 };
134
+ }
135
+ }
136
+ async function getDescribe(git) {
137
+ try {
138
+ const output = await git.raw(["describe", "--always"]);
139
+ return {
140
+ describe: removeLineBreak(output)
141
+ };
142
+ } catch (error) {
143
+ return {
144
+ describe: void 0
145
+ };
146
+ }
147
+ }
148
+ async function getGitHubUrl(git) {
149
+ const remotes = await git.getRemotes(true);
150
+ const origin = remotes.find((remote) => remote.name === "origin");
151
+ const url = origin?.refs.fetch;
152
+ if (url) {
153
+ const parsed = parseGitUrl(url);
154
+ if (parsed.resource === "github.com" && parsed.full_name) {
155
+ return { github: `https://github.com/${parsed.full_name}` };
156
+ }
157
+ }
158
+ return { github: void 0 };
159
+ }
160
+
161
+ class BuildGitModule extends BuildInfoModule {
162
+ constructor(root, options) {
163
+ super("git", root, options);
164
+ }
165
+ async load(ctx, id) {
166
+ const { root, options } = this;
167
+ const info = await getRepoInfo(root, options?.git);
168
+ if (info && options?.github) {
169
+ info.github = options.github;
170
+ }
171
+ if (!info) {
172
+ ctx.warn("This may not be a git repo");
173
+ }
174
+ const keys = [
175
+ .../* @__PURE__ */ new Set([
176
+ "github",
177
+ "sha",
178
+ "abbreviatedSha",
179
+ "branch",
180
+ "tag",
181
+ "tags",
182
+ "lastTag",
183
+ "describe",
184
+ "author",
185
+ "authorEmail",
186
+ "authorDate",
187
+ "committer",
188
+ "committerEmail",
189
+ "committerDate",
190
+ "commitMessage",
191
+ ...Object.keys(options?.git ?? {})
192
+ ])
193
+ ];
194
+ const gen = (key) => {
195
+ return `export const ${key} = ${info ? JSON.stringify(info[key]) : "null"}`;
196
+ };
197
+ return [
198
+ // Support legacy ~build/info module
199
+ id.endsWith("info") ? `export const CI = ${ci.isCI ? `"${ci.name}"` : "null"}` : ``,
200
+ ...keys.map((key) => gen(key))
201
+ ].join("\n");
202
+ }
203
+ }
204
+
205
+ const execAsync = promisify(exec);
206
+ async function getSvnInfo(root, extra = {}) {
207
+ try {
208
+ const svnDir = await execSync("svn info --show-item wc-root", root);
209
+ if (!svnDir) {
210
+ return void 0;
211
+ }
212
+ const [info, lastCommit, log, extraResult] = await Promise.all([
213
+ getSvnBasicInfo(root),
214
+ getLastCommit(root),
215
+ getCommitLog(root),
216
+ Promise.all(
217
+ Object.entries(extra).map(async ([key, fn]) => {
218
+ return [key, await fn(null)];
219
+ })
220
+ )
221
+ ]);
222
+ return {
223
+ ...info,
224
+ ...lastCommit,
225
+ ...log,
226
+ ...Object.fromEntries(extraResult)
227
+ };
228
+ } catch (error) {
229
+ return void 0;
230
+ }
231
+ }
232
+ async function getSvnBasicInfo(root) {
233
+ try {
234
+ const output = await execSync("svn info", root);
235
+ const lines = output.split("\n");
236
+ const info = {};
237
+ for (const line of lines) {
238
+ const match = line.match(/^([^:]+):\s*(.+)$/);
239
+ if (match) {
240
+ const key = toCamelCase(match[1].trim());
241
+ info[key] = match[2].trim();
242
+ }
243
+ }
244
+ return {
245
+ url: info["URL"],
246
+ repositoryRoot: info["Repository Root"],
247
+ repositoryUuid: info["Repository UUID"],
248
+ revision: info["Revision"],
249
+ nodeKind: info["Node Kind"],
250
+ lastChangedRev: info["Last Changed Rev"],
251
+ lastChangedDate: info["Last Changed Date"],
252
+ lastChangedAuthor: info["Last Changed Author"]
253
+ };
254
+ } catch (error) {
255
+ return {
256
+ url: void 0,
257
+ repositoryRoot: void 0,
258
+ repositoryUuid: void 0,
259
+ revision: void 0,
260
+ nodeKind: void 0,
261
+ lastChangedRev: void 0,
262
+ lastChangedDate: void 0,
263
+ lastChangedAuthor: void 0
264
+ };
265
+ }
266
+ }
267
+ async function getLastCommit(root) {
268
+ try {
269
+ const output = await execSync("svn log -l 1 --xml", root);
270
+ const logEntry = parseSvnXmlLog(output);
271
+ return {
272
+ sha: logEntry?.revision,
273
+ abbreviatedSha: logEntry?.revision,
274
+ commitMessage: logEntry?.msg,
275
+ author: logEntry?.author,
276
+ authorDate: logEntry?.date,
277
+ authorEmail: void 0
278
+ // SVN 不包含邮箱信息
279
+ };
280
+ } catch (error) {
281
+ return {
282
+ sha: void 0,
283
+ abbreviatedSha: void 0,
284
+ commitMessage: void 0,
285
+ author: void 0,
286
+ authorDate: void 0,
287
+ authorEmail: void 0
288
+ };
289
+ }
290
+ }
291
+ async function getCommitLog(root) {
292
+ try {
293
+ const output = await execSync("svn log -l 10 --xml", root);
294
+ const logs = parseSvnXmlLogs(output);
295
+ const lastTag = await getBranchOrTag(root);
296
+ return {
297
+ branch: lastTag || void 0,
298
+ tag: lastTag || void 0,
299
+ tags: logs.map((log) => log.revision),
300
+ lastTag: lastTag || void 0,
301
+ describe: `r${logs[0]?.revision || ""}`
302
+ };
303
+ } catch (error) {
304
+ return {
305
+ branch: void 0,
306
+ tag: void 0,
307
+ tags: [],
308
+ lastTag: void 0,
309
+ describe: void 0
310
+ };
311
+ }
312
+ }
313
+ async function getBranchOrTag(root) {
314
+ try {
315
+ const url = await execSync("svn info --show-item url", root);
316
+ if (url.includes("/trunk/")) {
317
+ return "trunk";
318
+ }
319
+ if (url.includes("/branches/")) {
320
+ const match = url.match(/\/branches\/([^\/]+)/);
321
+ return match ? match[1] : void 0;
322
+ }
323
+ if (url.includes("/tags/")) {
324
+ const match = url.match(/\/tags\/([^\/]+)/);
325
+ return match ? match[1] : void 0;
326
+ }
327
+ return void 0;
328
+ } catch (error) {
329
+ return void 0;
330
+ }
331
+ }
332
+ function parseSvnXmlLog(xml) {
333
+ try {
334
+ const entryMatch = xml.match(/<logentry[^>]*revision="(\d+)"[^>]*>/);
335
+ if (!entryMatch) return null;
336
+ const authorMatch = xml.match(/<author>([^<]+)<\/author>/);
337
+ const dateMatch = xml.match(/<date>([^<]+)<\/date>/);
338
+ const msgMatch = xml.match(/<msg>([^<]*)<\/msg>/);
339
+ return {
340
+ revision: entryMatch[1],
341
+ author: authorMatch?.[1] || "",
342
+ date: dateMatch?.[1] || "",
343
+ msg: msgMatch?.[1] || ""
344
+ };
345
+ } catch (error) {
346
+ return null;
347
+ }
348
+ }
349
+ function parseSvnXmlLogs(xml) {
350
+ try {
351
+ const entries = [];
352
+ const regex = /<logentry[^>]*revision="(\d+)"[^>]*>[\s\S]*?<author>([^<]+)<\/author>[\s\S]*?<date>([^<]+)<\/date>[\s\S]*?<msg>([^<]*)<\/msg>[\s\S]*?<\/logentry>/g;
353
+ let match;
354
+ while ((match = regex.exec(xml)) !== null) {
355
+ entries.push({
356
+ revision: match[1],
357
+ author: match[2],
358
+ date: match[3],
359
+ msg: match[4]
360
+ });
361
+ }
362
+ return entries;
363
+ } catch (error) {
364
+ return [];
365
+ }
366
+ }
367
+ function toCamelCase(str) {
368
+ return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
369
+ return index === 0 ? word.toLowerCase() : word.toUpperCase();
370
+ }).replace(/\s+/g, "");
371
+ }
372
+ function execSync(command, cwd) {
373
+ return execAsync(command, { cwd, encoding: "utf-8" }).then((res) => res.stdout.trim()).catch(() => "");
374
+ }
375
+
376
+ class BuildSvnModule extends BuildInfoModule {
377
+ constructor(root, options) {
378
+ super("svn", root, options);
379
+ }
380
+ async load(ctx, id) {
381
+ const { root, options } = this;
382
+ const info = await getSvnInfo(root, options?.svn);
383
+ if (!info) {
384
+ ctx.warn("This may not be a svn repo");
385
+ }
386
+ const keys = [
387
+ .../* @__PURE__ */ new Set([
388
+ "url",
389
+ "repositoryRoot",
390
+ "repositoryUuid",
391
+ "revision",
392
+ "nodeKind",
393
+ "lastChangedRev",
394
+ "lastChangedDate",
395
+ "lastChangedAuthor",
396
+ "sha",
397
+ "abbreviatedSha",
398
+ "commitMessage",
399
+ "author",
400
+ "authorDate",
401
+ "authorEmail",
402
+ "branch",
403
+ "tag",
404
+ "tags",
405
+ "lastTag",
406
+ "describe",
407
+ ...Object.keys(options?.svn ?? {})
408
+ ])
409
+ ];
410
+ const gen = (key) => {
411
+ return `export const ${key} = ${info ? JSON.stringify(info[key]) : "null"}`;
412
+ };
413
+ return keys.map((key) => gen(key)).join("\n");
414
+ }
415
+ }
416
+
417
+ class LegacyInfoModule extends BuildGitModule {
418
+ constructor(root, options) {
419
+ super(root, options);
420
+ this.name = `${options.prefix ?? "~build"}/info`;
421
+ }
422
+ }
423
+
424
+ class BuildConsoleModule extends BuildInfoModule {
425
+ constructor(root, options) {
426
+ super("console", root, options);
427
+ }
428
+ load() {
429
+ const { environment = ["development", "production"] } = this.options.console ?? {};
430
+ return [
431
+ `import time from '~build/time';`,
432
+ `import { isCI } from '~build/ci';`,
433
+ `import { github } from '~build/git';`,
434
+ `import { name, version } from '~build/package';`,
435
+ ``,
436
+ `export const print = () => {`,
437
+ ` if (!${JSON.stringify(environment)}.includes(process.env.NODE_ENV)) return;`,
438
+ ` if (typeof import.meta?.env?.SSR !== 'undefined' && import.meta.env.SSR) return;`,
439
+ ` console.groupCollapsed('~build/console');`,
440
+ ` console.log('Project:', name);`,
441
+ ` console.log('Build-at:', time ? time.toLocaleString() : 'Unknown');`,
442
+ ` console.log('Environment:', \`${process.env.NODE_ENV}\${isCI ? '(ci)' : ''}\`);`,
443
+ ` console.log('Version:', version);`,
444
+ ` console.log('GitHub:', github);`,
445
+ ` console.groupEnd();`,
446
+ `};`,
447
+ ``,
448
+ `print();`
449
+ ].join("\n");
450
+ }
451
+ }
452
+
453
+ class BuildCIModule extends BuildInfoModule {
454
+ constructor(root, options) {
455
+ super("ci", root, options);
456
+ }
457
+ load() {
458
+ return [
459
+ `export const isCI = ${ci.isCI !== null ? ci.isCI ? "true" : "false" : "null"}`,
460
+ `export const isPR = ${ci.isPR !== null ? ci.isPR ? "true" : "false" : "null"}`,
461
+ `export const name = ${ci.name !== null ? `\`${ci.name}\`` : "null"}`
462
+ ].join("\n");
463
+ }
464
+ }
465
+
466
+ class BuildMetaModule extends BuildInfoModule {
467
+ constructor(root, options) {
468
+ super("meta", root, options);
469
+ }
470
+ async load() {
471
+ const { options } = this;
472
+ const get = () => {
473
+ if (!options?.meta) return {};
474
+ if (typeof options.meta === "function") {
475
+ return options.meta();
476
+ }
477
+ return options.meta;
478
+ };
479
+ const meta = await get();
480
+ const body = Object.entries(meta).map(
481
+ ([key, value]) => `export const ${key} = ${JSON.stringify(value, null, 2)};`
482
+ );
483
+ return body.length > 0 ? body.join("\n") : "export {};";
484
+ }
485
+ }
486
+
487
+ class BuildEnvModule extends BuildInfoModule {
488
+ constructor(root, options) {
489
+ super("env", root, options);
490
+ }
491
+ async load() {
492
+ const { options } = this;
493
+ const get = () => {
494
+ if (!options?.env) return {};
495
+ if (typeof options.env === "function") {
496
+ return options.env();
497
+ }
498
+ return options.env;
499
+ };
500
+ const cloudflare = options.cloudflare === true;
501
+ const meta = await get();
502
+ const body = Object.entries(meta).map(
503
+ ([key, value]) => !cloudflare ? `export const ${key} = (typeof import.meta?.env?.SSR !== 'undefined' && import.meta.env.SSR ? process?.env?.['${key.replace(/'/g, "\\\\")}'] : undefined) ?? ${JSON.stringify(value, null, 2)};` : `export const ${key} = ${JSON.stringify(value, null, 2)};`
504
+ );
505
+ return body.length > 0 ? body.join("\n") : "export {};";
506
+ }
507
+ }
508
+
509
+ class BuildPackageModule extends BuildInfoModule {
510
+ constructor(root, options) {
511
+ super("package", root, options);
512
+ }
513
+ load() {
514
+ const { root, options } = this;
515
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
516
+ const defaults = ["name", "version", "description", "keywords", "license", "author"];
517
+ const keys = new Set(
518
+ Array.isArray(options?.package) ? [...defaults, ...options.package] : typeof options?.package === "object" ? Object.entries(
519
+ Object.fromEntries([
520
+ ...defaults.map((d) => [d, true]),
521
+ ...Object.entries(options.package)
522
+ ])
523
+ ).filter(([k, v]) => !!v).map(([k, v]) => k) : defaults
524
+ );
525
+ const resolved = {
526
+ name: "",
527
+ version: "0.0.0",
528
+ description: "",
529
+ keywords: [],
530
+ license: "",
531
+ author: "",
532
+ ...pkg
533
+ };
534
+ const entries = [...keys].map((key) => [key, resolved[key]]);
535
+ return entries.map(([key, value]) => `export const ${key} = ${JSON.stringify(value, null, 2)};`).join("\n");
536
+ }
537
+ }
538
+
539
+ const UnpluginInfo = /* @__PURE__ */ createUnplugin(
540
+ (options = {}, meta) => {
541
+ const root = path.resolve(options?.root ?? process$1.cwd());
542
+ const modules = {
543
+ Time: new BuildTimeModule(root, options),
544
+ Git: new BuildGitModule(root, options),
545
+ Svn: new BuildSvnModule(root, options),
546
+ CI: new BuildCIModule(root, options),
547
+ Info: new LegacyInfoModule(root, options),
548
+ Console: new BuildConsoleModule(root, options),
549
+ Meta: new BuildMetaModule(root, options),
550
+ Env: new BuildEnvModule(root, options),
551
+ Package: new BuildPackageModule(root, options)
552
+ };
553
+ return {
554
+ name: "unplugin-info",
555
+ async buildStart() {
556
+ await Promise.all(Object.values(modules).map((mod) => mod.buildStart(this)));
557
+ },
558
+ async buildEnd() {
559
+ await Promise.all(Object.values(modules).map((mod) => mod.buildEnd(this)));
560
+ },
561
+ resolveId(id) {
562
+ if (Object.values(modules).map((m) => m.name).includes(id)) {
563
+ return `\0${id}`;
564
+ }
565
+ },
566
+ loadInclude(id) {
567
+ if (!id.startsWith("\0")) return false;
568
+ id = id.slice(1);
569
+ return Object.values(modules).map((m) => m.name).includes(id);
570
+ },
571
+ async load(id) {
572
+ if (!id.startsWith("\0")) return;
573
+ id = id.slice(1);
574
+ for (const mod of Object.values(modules)) {
575
+ if (id === mod.name) {
576
+ if (id === modules.Info.name) {
577
+ this.warn(
578
+ `${modules.Info.name} is deprecated, please migrate to ${modules.Git.name} and ${modules.CI.name}.`
579
+ );
580
+ }
581
+ if (id === modules.Env.name && meta.framework !== "vite") {
582
+ this.warn(`${modules.Env.name} is only supported in Vite.`);
583
+ return;
584
+ }
585
+ return mod.load(this, id);
586
+ }
587
+ }
588
+ },
589
+ vite: {
590
+ handleHotUpdate({ file, server }) {
591
+ if (file === normalizePath(path.resolve(root, "package.json"))) {
592
+ const module = server.moduleGraph.getModuleById("\0" + modules.Package.name);
593
+ if (module) {
594
+ server.moduleGraph.invalidateModule(module);
595
+ server.ws.send({
596
+ type: "full-reload"
597
+ });
598
+ }
599
+ }
600
+ }
601
+ }
602
+ };
603
+ }
604
+ );
605
+ function normalizePath(filename) {
606
+ return filename.split(path.win32.sep).join(path.posix.sep);
607
+ }
608
+
609
+ export { UnpluginInfo as U };