@staticbolt/core 1.0.0-beta.11 → 1.0.0-beta.13

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.
@@ -1,18 +1,18 @@
1
- import { A as isHtmlMetadata, B as DependencyTracker, C as PrintFormattedError, D as filterScriptMetadata, E as traverse, F as isSvgMetadata, I as isTextAssetMetadata, L as isWebManifestMetadata, M as isPackageMetadata, N as isScriptMetadata, O as filterStyleMetadata, P as isStyleMetadata, R as isScriptType, S as valueOrError, T as generator, _ as mergeMaps, b as safeReadFileSync, c as downloadContent, d as hashContent, f as humanReadableBytes, h as isURL, j as isMarkdownMetadata, k as isBinaryAssetMetadata, l as escapeHtml, n as bytesToKB, s as cloneObject, w as printFmtError, z as METADATA_TYPES } from "../utilities-CZmLMi93.mjs";
2
- import { _ as CUSTOM_ATTRIBUTES, a as extname, c as join, d as parse$2, g as CONFIG_FILE_NAME, h as resolve, i as dirname, l as matchPath, m as replaceExtension, n as createLog, o as isAbsolute, p as relative, r as basename, s as isSubpath, t as Log, u as normalize } from "../logger-BfIn1ytK.mjs";
1
+ import { A as isStyleMetadata, C as filterScriptMetadata, D as isMarkdownMetadata, E as isHtmlMetadata, F as METADATA_TYPES, H as isValidRelativePath, I as Resolver, L as readJsonFile, M as isTextAssetMetadata, N as isWebManifestMetadata, O as isPackageMetadata, P as isScriptType, S as traverse, T as isBinaryAssetMetadata, U as splitHtmlLink, V as valueOrError, W as DependencyTracker, _ as mergeMaps, b as printFmtError, c as downloadContent, d as hashContent, f as humanReadableBytes, h as isURL, j as isSvgMetadata, k as isScriptMetadata, l as escapeHtml, n as bytesToKB, s as cloneObject, w as filterStyleMetadata, x as generator, y as PrintFormattedError, z as safeReadFileSync } from "../utilities-Bu5rdDC9.mjs";
2
+ import { _ as resolve, a as basename, c as isAbsolute, d as matchPath, f as normalize, g as replaceExtension, h as relative, i as createLog, l as isSubpath, n as CUSTOM_ATTRIBUTES, o as dirname, p as parse$2, r as Log, s as extname, t as CONFIG_FILE_NAME, u as join } from "../common-Bkh8-tjA.mjs";
3
3
  import { createRequire } from "node:module";
4
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, rmdirSync, unlinkSync, writeFileSync } from "node:fs";
4
5
  import nodePath from "node:path";
5
- import { HTMLElement, NodeType, parse } from "@staticbolt/node-html-parser";
6
6
  import c from "chalk";
7
+ import json5 from "json5";
8
+ import { HTMLElement, NodeType, parse } from "@staticbolt/node-html-parser";
7
9
  import postcss from "postcss";
8
10
  import { common, createEmphasize } from "emphasize";
9
- import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
10
11
  import { globSync } from "glob";
11
12
  import { minify_sync } from "terser";
12
13
  import * as esbuild from "esbuild";
13
14
  import * as t from "@babel/types";
14
15
  import sharp from "sharp";
15
- import json5 from "json5";
16
16
  import { generateSW } from "workbox-build";
17
17
  import { optimize } from "svgo";
18
18
  import postcssrc from "postcss-load-config";
@@ -47,46 +47,10 @@ import Fastify from "fastify";
47
47
  import { WebSocketServer } from "ws";
48
48
  import browserslistFn from "browserslist";
49
49
  import chokidar from "chokidar";
50
- import { ResolverFactory } from "oxc-resolver";
51
50
  import ttf2woff2 from "ttf2woff2";
52
51
  import * as z from "zod";
53
52
  import * as fontKit from "fontkit";
54
53
 
55
- //#region src/utilities/html-links.ts
56
- /**
57
- * Checks if the link is an HTML link (not a file link)
58
- *
59
- * @param source - The link
60
- * @returns
61
- */
62
- function isHtmlLink(source) {
63
- return /^(?:#|https?|mailto:|tel:|url\(|ftp:|data:|javascript:)/i.test(source);
64
- }
65
- function isValidRelativePath(source) {
66
- if (!source) return false;
67
- if (isAbsolute(source)) return false;
68
- if (isHtmlLink(source)) return false;
69
- return true;
70
- }
71
- function splitHtmlLink(url) {
72
- const qIndex = url.indexOf("?");
73
- const hIndex = url.indexOf("#");
74
- let delimIndex = -1;
75
- if (qIndex !== -1 && hIndex !== -1) delimIndex = Math.min(qIndex, hIndex);
76
- else if (qIndex !== -1) delimIndex = qIndex;
77
- else if (hIndex !== -1) delimIndex = hIndex;
78
- if (delimIndex !== -1) {
79
- const pathEnd = url[delimIndex - 1] === "/" ? delimIndex - 1 : delimIndex;
80
- return [url.slice(0, pathEnd), url.slice(pathEnd)];
81
- }
82
- if (url.endsWith("/")) {
83
- if (url === "/" || url === "./") return [url, ""];
84
- return [url.slice(0, -1), "/"];
85
- }
86
- return [url, ""];
87
- }
88
-
89
- //#endregion
90
54
  //#region src/helpers/find-deps.ts
91
55
  var DepsFinder = class {
92
56
  #depsMap = /* @__PURE__ */ new Map();
@@ -1170,7 +1134,8 @@ function copyAssetsPlugin(options = {}) {
1170
1134
  const publicFiles = globSync("**/*", {
1171
1135
  ignore,
1172
1136
  nodir: true,
1173
- cwd: join(this.root, publicDirectory)
1137
+ cwd: join(this.root, publicDirectory),
1138
+ dot: true
1174
1139
  });
1175
1140
  for (const file of publicFiles) {
1176
1141
  const inputFile = join(this.root, publicDirectory, file);
@@ -1583,20 +1548,6 @@ async function loadPrettier(filePath) {
1583
1548
  }
1584
1549
  }
1585
1550
 
1586
- //#endregion
1587
- //#region src/utilities/read-json-file.ts
1588
- /** Read a file and parse it as JSON safely. */
1589
- function readJsonFile(path, code) {
1590
- if (!code) {
1591
- const [fileString, readError] = safeReadFileSync(path, "utf8");
1592
- if (readError) return [null, readError];
1593
- code = fileString;
1594
- }
1595
- const [parsed, parseError] = valueOrError(json5.parse)(code);
1596
- if (parseError !== null) return [null, parseError];
1597
- return [parsed, null];
1598
- }
1599
-
1600
1551
  //#endregion
1601
1552
  //#region src/plugins/i18n/get-locales.ts
1602
1553
  function getLocals(options) {
@@ -3067,6 +3018,28 @@ function htmlBuildTimeScript(options = {}) {
3067
3018
  }
3068
3019
  for (const node of metadata.ast.querySelectorAll(query)) node.remove();
3069
3020
  }
3021
+ },
3022
+ lspHtmlData() {
3023
+ return {
3024
+ version: 1.1,
3025
+ tags: [{
3026
+ name: "script",
3027
+ attributes: [
3028
+ {
3029
+ name: buildAttribute,
3030
+ description: "This attribute is used to mark the script as build-time script."
3031
+ },
3032
+ {
3033
+ name: fullDomAttribute,
3034
+ description: "Opt into a full DOM context using `jsdom`. When not present, the lighter `@staticbolt/node-html-parser` is used instead."
3035
+ },
3036
+ {
3037
+ name: contextAttribute,
3038
+ description: "Pass global context object as JSON to be available in the script during execution."
3039
+ }
3040
+ ]
3041
+ }]
3042
+ };
3070
3043
  }
3071
3044
  };
3072
3045
  }
@@ -3326,6 +3299,32 @@ function htmlBundleScriptPlugin(options = {}) {
3326
3299
  node.textContent = "";
3327
3300
  this.addMetadata(newScriptMetadata);
3328
3301
  }
3302
+ },
3303
+ lspHtmlData() {
3304
+ return {
3305
+ version: 1.1,
3306
+ tags: [{
3307
+ name: "script",
3308
+ attributes: [
3309
+ {
3310
+ name: bundleAttribute,
3311
+ description: "Enable script bundling."
3312
+ },
3313
+ {
3314
+ name: bundleOutAttribute,
3315
+ description: "Specify the output path for bundled scripts relative to the output directory.\nIf the script has a `src` attribute, the output path will default to `{filename}.bundle.js`.\nIf the script has no `src` attribute, the default behavior is to keep the script inline."
3316
+ },
3317
+ {
3318
+ name: externalsAttribute,
3319
+ description: `Glob patterns list to treat as external during bundling. (semicolon-separated)\n\nDefaults to "${defaultExternal.join(";")}".`
3320
+ },
3321
+ {
3322
+ name: externalsExcludeAttribute,
3323
+ description: `Glob patterns that exempt files from being treated as external, even if they match \`externals\`. (semicolon-separated)\n\nDefaults to "${defaultExternalExclude.join(";")}".`
3324
+ }
3325
+ ]
3326
+ }]
3327
+ };
3329
3328
  }
3330
3329
  };
3331
3330
  }
@@ -3395,6 +3394,24 @@ function htmlBundleStylePlugin(options = {}) {
3395
3394
  continue;
3396
3395
  }
3397
3396
  }
3397
+ },
3398
+ lspHtmlData() {
3399
+ return {
3400
+ version: 1.1,
3401
+ tags: [{
3402
+ name: "link",
3403
+ attributes: [{
3404
+ name: bundleAttribute,
3405
+ description: "Enable style bundling."
3406
+ }]
3407
+ }, {
3408
+ name: "style",
3409
+ attributes: [{
3410
+ name: bundleAttribute,
3411
+ description: "Enable style bundling."
3412
+ }]
3413
+ }]
3414
+ };
3398
3415
  }
3399
3416
  };
3400
3417
  }
@@ -3409,6 +3426,16 @@ function htmlFragmentPlugin(options = {}) {
3409
3426
  if (!isHtmlMetadata(metadata)) return;
3410
3427
  const elements = metadata.ast.querySelectorAll(tag);
3411
3428
  for (const node of elements) node.replaceWith(node.innerHTML.trim());
3429
+ },
3430
+ lspHtmlData() {
3431
+ return {
3432
+ version: 1.1,
3433
+ tags: [{
3434
+ name: tag,
3435
+ description: "At build time, this tag is replaced with its contents.",
3436
+ attributes: []
3437
+ }]
3438
+ };
3412
3439
  }
3413
3440
  };
3414
3441
  }
@@ -3504,6 +3531,18 @@ function htmlIifeScriptPlugin(options = {}) {
3504
3531
  continue;
3505
3532
  }
3506
3533
  }
3534
+ },
3535
+ lspHtmlData() {
3536
+ return {
3537
+ version: 1.1,
3538
+ tags: [{
3539
+ name: "script",
3540
+ attributes: [{
3541
+ name: iifeAttribute,
3542
+ description: "Enabling this will wrap the script content in an IIFE (Immediately Invoked Function Expression).\n\nWorks only with inline global scripts."
3543
+ }]
3544
+ }]
3545
+ };
3507
3546
  }
3508
3547
  };
3509
3548
  }
@@ -3550,6 +3589,18 @@ function htmlInlineScriptPlugin(options = {}) {
3550
3589
  metadata.scriptsMetadataList.set(metadataID, scriptMetadataClone);
3551
3590
  scriptTag.removeAttribute("src");
3552
3591
  }
3592
+ },
3593
+ lspHtmlData() {
3594
+ return {
3595
+ version: 1.1,
3596
+ tags: [{
3597
+ name: "script",
3598
+ attributes: [{
3599
+ name: inlineAttribute,
3600
+ description: "Enable inlining external scripts directly into the HTML at build time. It supports local files, remote URLs."
3601
+ }]
3602
+ }]
3603
+ };
3553
3604
  }
3554
3605
  };
3555
3606
  }
@@ -3615,6 +3666,18 @@ function htmlInlineStylePlugin(options = {}) {
3615
3666
  const attributesString = Object.entries(linkTag.attrs).map(([name, value]) => `${name}="${value}"`).join(" ");
3616
3667
  linkTag.replaceWith(`<style ${attributesString}></style>`);
3617
3668
  }
3669
+ },
3670
+ lspHtmlData() {
3671
+ return {
3672
+ version: 1.1,
3673
+ tags: [{
3674
+ name: "link",
3675
+ attributes: [{
3676
+ name: inlineAttribute,
3677
+ description: "Enable inlining external stylesheets directly into the HTML at build time. It supports both local files and remote URLs."
3678
+ }]
3679
+ }]
3680
+ };
3618
3681
  }
3619
3682
  };
3620
3683
  }
@@ -3689,6 +3752,18 @@ function HtmlInlineSvgPlugin(options = {}) {
3689
3752
  for (const [attribute, value] of Object.entries(node.attrs)) svgElement.setAttribute(attribute, value);
3690
3753
  node.replaceWith(svgElement);
3691
3754
  }
3755
+ },
3756
+ lspHtmlData() {
3757
+ return {
3758
+ version: 1.1,
3759
+ tags: [{
3760
+ name: "svg",
3761
+ attributes: [{
3762
+ name: inlineAttribute,
3763
+ description: "Enable inlining external SVGs directly into the HTML at build time. It supports both local files and remote URLs."
3764
+ }]
3765
+ }]
3766
+ };
3692
3767
  }
3693
3768
  };
3694
3769
  }
@@ -3787,6 +3862,22 @@ function htmlInlineTextPlugin(options = {}) {
3787
3862
  const importers = deps.getImporters(id);
3788
3863
  for (const importer of importers) compileSet.add(importer);
3789
3864
  }
3865
+ },
3866
+ lspHtmlData() {
3867
+ return {
3868
+ version: 1.1,
3869
+ tags: [{
3870
+ name: tag,
3871
+ description: "At build time, this tag is replaced with the contents of the external text file.",
3872
+ attributes: [{
3873
+ name: sourceAttribute,
3874
+ description: "The path to the external text file."
3875
+ }, {
3876
+ name: noEscapeAttribute,
3877
+ description: "Disable HTML escaping."
3878
+ }]
3879
+ }]
3880
+ };
3790
3881
  }
3791
3882
  };
3792
3883
  }
@@ -3845,6 +3936,35 @@ function htmlInsertPlugin(options = {}) {
3845
3936
  filePath: metadata.id
3846
3937
  });
3847
3938
  }
3939
+ },
3940
+ lspHtmlData() {
3941
+ return {
3942
+ version: 1.1,
3943
+ tags: [{
3944
+ name: tag,
3945
+ description: "At build time, inject HTML content into any target element on the page using a CSS selector at build time.",
3946
+ attributes: [
3947
+ {
3948
+ name: selectorAttribute,
3949
+ description: "The CSS selector of the target element."
3950
+ },
3951
+ {
3952
+ name: replaceAttribute,
3953
+ description: "Replace the target element with the contents of the custom insert element."
3954
+ },
3955
+ {
3956
+ name: whereAttribute,
3957
+ description: "The position of the inserted element.",
3958
+ values: [
3959
+ { name: "beforebegin" },
3960
+ { name: "afterbegin" },
3961
+ { name: "beforeend" },
3962
+ { name: "afterend" }
3963
+ ]
3964
+ }
3965
+ ]
3966
+ }]
3967
+ };
3848
3968
  }
3849
3969
  };
3850
3970
  }
@@ -3892,14 +4012,14 @@ function executeExpression$1(expressionString, data) {
3892
4012
  //#endregion
3893
4013
  //#region src/plugins/html-layout/html-layout-plugin.ts
3894
4014
  function htmlLayoutPlugin(options = {}) {
3895
- const tags = options.tags ?? ["layout", "part"];
4015
+ const layoutTags = options.tags ?? ["layout", "part"];
3896
4016
  const sourceAttribute = options.layoutSourceAttribute ?? "src";
3897
4017
  const dataSourceAttribute = options.dataSourceAttribute ?? "dataSource";
3898
4018
  const dataJsonAttribute = options.dataJsonAttribute ?? "dataJson";
3899
4019
  const alwaysIncludeAttribute = options.alwaysIncludeAttribute ?? "always-include";
3900
4020
  const addAttributeAttribute = options.addAttributeAttribute ?? "add-attr";
3901
4021
  const removeAttributeAttribute = options.removeAttributeAttribute ?? "remove-attr";
3902
- const query = tags.join(",");
4022
+ const query = layoutTags.join(",");
3903
4023
  const printFmtError = PrintFormattedError.create({ function: htmlLayoutPlugin });
3904
4024
  const htmlLayoutMetadataCache = [];
3905
4025
  /**
@@ -3909,12 +4029,12 @@ function htmlLayoutPlugin(options = {}) {
3909
4029
  const dataSourceCache = /* @__PURE__ */ new Map();
3910
4030
  function isLayoutPath(path) {
3911
4031
  const fileName = basename(path);
3912
- return tags.some((tag) => fileName.endsWith(`.${tag}.html`));
4032
+ return layoutTags.some((tag) => fileName.endsWith(`.${tag}.html`));
3913
4033
  }
3914
4034
  return {
3915
4035
  name: "html-layout",
3916
4036
  load(content, relativePath, { type }) {
3917
- if (type && !tags.includes(type)) return;
4037
+ if (type && !layoutTags.includes(type)) return;
3918
4038
  if (!isLayoutPath(relativePath)) return;
3919
4039
  const textAssetMetadata = {
3920
4040
  type: METADATA_TYPES.TextAsset,
@@ -3953,7 +4073,7 @@ function htmlLayoutPlugin(options = {}) {
3953
4073
  }
3954
4074
  if (isMarkdownMetadata(metadata)) for (const [key, source] of Object.entries(metadata.ast.frontmatter)) {
3955
4075
  if (!source) continue;
3956
- if (tags.includes(key) || key === dataSourceAttribute) sources.push({
4076
+ if (layoutTags.includes(key) || key === dataSourceAttribute) sources.push({
3957
4077
  get source() {
3958
4078
  return source;
3959
4079
  },
@@ -4178,7 +4298,7 @@ function htmlLayoutPlugin(options = {}) {
4178
4298
  return;
4179
4299
  }
4180
4300
  if (isMarkdownMetadata(metadata)) {
4181
- const tag = Object.keys(metadata.ast.frontmatter).find((key) => tags.includes(key));
4301
+ const tag = Object.keys(metadata.ast.frontmatter).find((key) => layoutTags.includes(key));
4182
4302
  if (!tag) return;
4183
4303
  let attributesString = "";
4184
4304
  for (const [key, value] of Object.entries(metadata.ast.frontmatter)) attributesString += `${key === tag ? sourceAttribute : key}="${value}" `;
@@ -4190,6 +4310,56 @@ function htmlLayoutPlugin(options = {}) {
4190
4310
  };
4191
4311
  return;
4192
4312
  }
4313
+ },
4314
+ lspHtmlData() {
4315
+ const attributes = [
4316
+ {
4317
+ name: sourceAttribute,
4318
+ description: "The path to the layout to use."
4319
+ },
4320
+ {
4321
+ name: dataSourceAttribute,
4322
+ description: "The path for a JSON file containing data for the layout."
4323
+ },
4324
+ {
4325
+ name: dataJsonAttribute,
4326
+ description: "The layout data in JSON format."
4327
+ }
4328
+ ];
4329
+ const alwaysInclude = {
4330
+ name: alwaysIncludeAttribute,
4331
+ description: "When using a layout more than once on the same page. Always include this script/style/link[rel='stylesheet'] even if it is already present."
4332
+ };
4333
+ const tags = [
4334
+ {
4335
+ name: "script",
4336
+ attributes: [alwaysInclude]
4337
+ },
4338
+ {
4339
+ name: "link",
4340
+ attributes: [alwaysInclude]
4341
+ },
4342
+ {
4343
+ name: "style",
4344
+ attributes: [alwaysInclude]
4345
+ }
4346
+ ];
4347
+ for (const tag of layoutTags) tags.push({
4348
+ name: tag,
4349
+ description: `This tag allows inlining a \`${tag}\` file.`,
4350
+ attributes
4351
+ });
4352
+ return {
4353
+ version: 1.1,
4354
+ tags,
4355
+ globalAttributes: [{
4356
+ name: addAttributeAttribute,
4357
+ description: "Inside a layout file only.Prefix for conditionally adding boolean attributes.Append the target attribute name as a suffix — `add-attr-open`, `add-attr-disabled`, etc. The value is a JS expression evaluated after placeholder resolution; if it is non-empty and not `\"false\"`, the named attribute is added to the element. Multiple `add-attr-*` attributes can appear on the same element."
4358
+ }, {
4359
+ name: removeAttributeAttribute,
4360
+ description: "Inside a layout file only.Prefix for conditionally removing boolean attributes.Append the target attribute name as a suffix — `remove-attr-open`, `remove-attr-disabled`, etc. The value is a JS expression evaluated after placeholder resolution; if it is non-empty and not `\"false\"`, the named attribute is removed from the element. Multiple `remove-attr-*` attributes can appear on the same element."
4361
+ }]
4362
+ };
4193
4363
  }
4194
4364
  };
4195
4365
  }
@@ -4257,7 +4427,22 @@ function htmlMarkdownPlugin(options = {}) {
4257
4427
  });
4258
4428
  continue;
4259
4429
  }
4260
- node.innerHTML = await markdownMetadata.ast.render();
4430
+ const asHtmlString = await markdownMetadata.ast.render();
4431
+ const htmlMetadata = await this.load(metadata.filePath, {
4432
+ code: asHtmlString,
4433
+ type: "html"
4434
+ });
4435
+ if (!isHtmlMetadata(htmlMetadata)) {
4436
+ printFmtError("Invalid HTML file:", metadata.filePath, {
4437
+ node,
4438
+ filePath: metadata.id
4439
+ });
4440
+ continue;
4441
+ }
4442
+ const metadataList = await this.resolveAndLoad(htmlMetadata);
4443
+ this.addMetadata(metadataList.slice(1));
4444
+ await this.transformAndSync(metadataList);
4445
+ node.set_content(htmlMetadata.ast.children);
4261
4446
  }
4262
4447
  const currentSources = /* @__PURE__ */ new Set();
4263
4448
  const markdowns = metadata.ast.querySelectorAll(markdownTag);
@@ -4281,8 +4466,23 @@ function htmlMarkdownPlugin(options = {}) {
4281
4466
  continue;
4282
4467
  }
4283
4468
  currentSources.add(sourceRelative);
4284
- const content = await markdownMetadata.ast.render();
4285
- node.replaceWith(content);
4469
+ const asHtmlString = await markdownMetadata.ast.render();
4470
+ const htmlMetadata = await this.load(sourceRelative, {
4471
+ code: asHtmlString,
4472
+ type: "html"
4473
+ });
4474
+ if (!isHtmlMetadata(htmlMetadata)) {
4475
+ printFmtError("Invalid HTML file:", sourceRelative, {
4476
+ node,
4477
+ filePath: metadata.id
4478
+ });
4479
+ continue;
4480
+ }
4481
+ const metadataList = await this.resolveAndLoad(htmlMetadata);
4482
+ this.addMetadata(metadataList.slice(1));
4483
+ await this.transformAndSync(metadataList);
4484
+ await this.rebase(htmlMetadata, join(this.root, metadata.filePath));
4485
+ node.replaceWith(...htmlMetadata.ast.children);
4286
4486
  }
4287
4487
  deps.update(metadata.id, currentSources);
4288
4488
  },
@@ -4295,6 +4495,23 @@ function htmlMarkdownPlugin(options = {}) {
4295
4495
  const importers = deps.getImporters(id);
4296
4496
  for (const importer of importers) compileSet.add(importer);
4297
4497
  }
4498
+ },
4499
+ lspHtmlData() {
4500
+ return {
4501
+ version: 1.1,
4502
+ globalAttributes: [{
4503
+ name: mdAttribute,
4504
+ description: "Render the contents of this element as markdown."
4505
+ }],
4506
+ tags: [{
4507
+ name: markdownTag,
4508
+ description: "This tag lets you render Markdown files inside HTML.",
4509
+ attributes: [{
4510
+ name: sourceAttribute,
4511
+ description: "The path to the external markdown file."
4512
+ }]
4513
+ }]
4514
+ };
4298
4515
  }
4299
4516
  };
4300
4517
  }
@@ -4900,8 +5117,8 @@ function getPreloadInfo(filePath) {
4900
5117
  //#region src/plugins/html-preload/html-preload-plugin.ts
4901
5118
  function htmlPreloadPlugin(options = {}) {
4902
5119
  const preloadAttribute = options.preloadAttribute ?? "preload";
4903
- const includeAttribute = options.includeAttribute ?? "include";
4904
- const excludeAttribute = options.excludeAttribute ?? "exclude";
5120
+ const includeAttribute = options.includeAttribute ?? "preload-include";
5121
+ const excludeAttribute = options.excludeAttribute ?? "preload-exclude";
4905
5122
  const asTypes = [
4906
5123
  "script",
4907
5124
  "style",
@@ -4980,6 +5197,37 @@ function htmlPreloadPlugin(options = {}) {
4980
5197
  head.insertAdjacentHTML("beforeend", linkTags.join("\n"));
4981
5198
  }
4982
5199
  }
5200
+ },
5201
+ lspHtmlData() {
5202
+ const attributes = [
5203
+ {
5204
+ name: preloadAttribute,
5205
+ description: `Enable preloading.
5206
+ Automatically generates \`<link rel="preload">\` tags for the dependencies of your scripts and stylesheets.
5207
+ This tells the browser to start fetching those files early, before they are discovered through normal parsing.
5208
+
5209
+ You can narrow down the files to preload by specifying a space-separated list of dependency types, additionally you can use the \`${includeAttribute}\` and \`${excludeAttribute}\` attributes.`,
5210
+ values: asTypes.map((type) => ({ name: type }))
5211
+ },
5212
+ {
5213
+ name: includeAttribute,
5214
+ description: `Glob patterns list to include when using the \`${preloadAttribute}\` attribute. (semicolon-separated)`
5215
+ },
5216
+ {
5217
+ name: excludeAttribute,
5218
+ description: `Glob patterns list to exclude when using the \`${preloadAttribute}\` attribute. (semicolon-separated)`
5219
+ }
5220
+ ];
5221
+ return {
5222
+ version: 1.1,
5223
+ tags: [{
5224
+ name: "link",
5225
+ attributes
5226
+ }, {
5227
+ name: "script",
5228
+ attributes
5229
+ }]
5230
+ };
4983
5231
  }
4984
5232
  };
4985
5233
  }
@@ -6257,207 +6505,6 @@ function printExecutionTime(executionTime) {
6257
6505
  console.log();
6258
6506
  }
6259
6507
 
6260
- //#endregion
6261
- //#region src/resolver/get-aliases.ts
6262
- /** Gets path aliases from `tsconfig.json` */
6263
- function getPathAliases(root) {
6264
- const [tsconfig, tsconfigParseError] = readTsconfig(root);
6265
- if (tsconfigParseError !== null) return [null, tsconfigParseError];
6266
- const paths = tsconfig.paths ?? {};
6267
- const alias = {};
6268
- for (const key in paths) {
6269
- const aliasName = key.replace(/\*$/, "");
6270
- alias[aliasName] = paths[key][0].replace(/\*$/, "");
6271
- }
6272
- return [alias, null];
6273
- }
6274
- function readTsconfig(root) {
6275
- const [tsconfig, tsconfigParseError] = readJsonFile(join(root, "tsconfig.json"));
6276
- if (tsconfigParseError !== null) return [null, tsconfigParseError];
6277
- if (!tsconfig.compilerOptions) return [null, /* @__PURE__ */ new Error("[readTsconfig] No compilerOptions found in tsconfig.json")];
6278
- return [tsconfig.compilerOptions, null];
6279
- }
6280
-
6281
- //#endregion
6282
- //#region src/resolver/resolver.ts
6283
- const nodeModulesResolver = new ResolverFactory({
6284
- conditionNames: [
6285
- "browser",
6286
- "import",
6287
- "default"
6288
- ],
6289
- extensions: [
6290
- ".js",
6291
- ".json",
6292
- ".node",
6293
- ".css"
6294
- ],
6295
- symlinks: false
6296
- });
6297
- var Resolver = class Resolver {
6298
- root;
6299
- aliases = {};
6300
- notFound = /* @__PURE__ */ new Set();
6301
- files = /* @__PURE__ */ new Set();
6302
- directories = /* @__PURE__ */ new Set();
6303
- static JS_EXTENSIONS = new Set([
6304
- ".js",
6305
- ".mjs",
6306
- ".cjs",
6307
- ".jsx",
6308
- ".ts",
6309
- ".mts",
6310
- ".cts",
6311
- ".tsx"
6312
- ]);
6313
- static HTML_EXTENSIONS = new Set([".html", ".md"]);
6314
- constructor(root) {
6315
- this.root = root;
6316
- const [aliases] = getPathAliases(root);
6317
- if (aliases) this.aliases = aliases;
6318
- }
6319
- resolve(sourceOrLink, filePath) {
6320
- if (!isValidRelativePath(sourceOrLink)) return;
6321
- const absFilePath = isAbsolute(filePath) ? filePath : join(this.root, filePath);
6322
- const [source, suffix] = splitHtmlLink(sourceOrLink);
6323
- if (isAbsolute(source)) return;
6324
- const checkDirectory = suffix === "/";
6325
- const absSource = join(dirname(absFilePath), source);
6326
- const foundFile = this.findFile(absSource, checkDirectory);
6327
- if (foundFile) return {
6328
- path: foundFile,
6329
- exists: true,
6330
- suffix
6331
- };
6332
- const sourceForAlias = suffix === "/" ? source + "/" : source;
6333
- const resolvedPathAlias = Resolver.resolvePathAlias(sourceForAlias, this.aliases);
6334
- if (resolvedPathAlias) {
6335
- const absSource = join(this.root, resolvedPathAlias);
6336
- const foundFile = this.findFile(absSource, checkDirectory);
6337
- const isFileAlias = sourceForAlias in this.aliases && !sourceForAlias.endsWith("/");
6338
- if (!foundFile && !this.notFound.has(absSource.replace(/\/$/, ""))) {
6339
- this.notFound.add(absSource.replace(/\/$/, ""));
6340
- Log.warn(`[resolver] Source "${sourceOrLink}" found in "${filePath}" was resolved to "${resolvedPathAlias}", but the file is missing.`);
6341
- }
6342
- return {
6343
- path: foundFile ?? absSource,
6344
- exists: !!foundFile,
6345
- suffix,
6346
- isFileAlias,
6347
- isDirAlias: !isFileAlias
6348
- };
6349
- }
6350
- if (!source.startsWith(".")) {
6351
- const resolverResult = nodeModulesResolver.sync(this.root, source);
6352
- if (resolverResult.path) return {
6353
- path: resolverResult.path,
6354
- suffix,
6355
- exists: true,
6356
- isPackage: true
6357
- };
6358
- }
6359
- if (source.startsWith("./") || source.startsWith("../")) {
6360
- if (!this.notFound.has(absSource)) {
6361
- this.notFound.add(absSource);
6362
- Log.warn(`[resolver] Source "${sourceOrLink}" found in "${filePath}" points to a non-existent file.`);
6363
- }
6364
- return {
6365
- path: absSource,
6366
- suffix,
6367
- exists: false
6368
- };
6369
- }
6370
- }
6371
- resolveAlias(source) {
6372
- return Resolver.resolvePathAlias(source, this.aliases);
6373
- }
6374
- normalize(filePath) {
6375
- return normalize(filePath);
6376
- }
6377
- static isFile(filePath) {
6378
- try {
6379
- return statSync(filePath).isFile();
6380
- } catch (error) {
6381
- const code = error.code;
6382
- if (code === "ENOENT" || code === "ENOTDIR") return false;
6383
- throw error;
6384
- }
6385
- }
6386
- /** Aliased path to path */
6387
- static resolvePathAlias(filePath, aliases) {
6388
- for (const [key, value] of Object.entries(aliases)) {
6389
- if (key.endsWith("/")) {
6390
- if (!filePath.startsWith(key)) continue;
6391
- return filePath.replace(key, value);
6392
- }
6393
- if (filePath === key) return value;
6394
- }
6395
- }
6396
- /** Path to aliased path */
6397
- static resolveAliasPath(filePath, aliases) {
6398
- let shortest;
6399
- for (const [key, value] of Object.entries(aliases)) {
6400
- if (key.endsWith("/")) {
6401
- if (!filePath.startsWith(value)) continue;
6402
- const aliased = filePath.replace(value, key);
6403
- if (!shortest || aliased.length < shortest.length) shortest = aliased;
6404
- continue;
6405
- }
6406
- if (filePath === value && (!shortest || key.length < shortest.length)) shortest = key;
6407
- }
6408
- return shortest ?? filePath;
6409
- }
6410
- /** Path to aliased path */
6411
- aliasPath(filePath) {
6412
- return Resolver.resolveAliasPath(filePath, this.aliases);
6413
- }
6414
- findFile(filePath, checkDirectory = false) {
6415
- if (this.files.has(filePath)) return filePath;
6416
- if (Resolver.isFile(filePath)) {
6417
- this.files.add(filePath);
6418
- return filePath;
6419
- }
6420
- const extension = extname(filePath);
6421
- if (!extension) {
6422
- for (const candidateExtension of [...Resolver.JS_EXTENSIONS, ...Resolver.HTML_EXTENSIONS]) {
6423
- const candidate = replaceExtension(filePath, candidateExtension);
6424
- if (this.files.has(candidate)) return candidate;
6425
- if (Resolver.isFile(candidate)) {
6426
- this.files.add(candidate);
6427
- return candidate;
6428
- }
6429
- }
6430
- const withIndex = join(filePath, "index");
6431
- for (const candidateExtension of Resolver.HTML_EXTENSIONS) {
6432
- const candidate = replaceExtension(withIndex, candidateExtension);
6433
- if (this.files.has(candidate)) return candidate;
6434
- if (Resolver.isFile(candidate)) {
6435
- this.files.add(candidate);
6436
- return candidate;
6437
- }
6438
- }
6439
- if (checkDirectory) {
6440
- if (this.directories.has(filePath)) return filePath;
6441
- if (existsSync(filePath)) {
6442
- this.directories.add(filePath);
6443
- return filePath;
6444
- }
6445
- }
6446
- return;
6447
- }
6448
- if (Resolver.JS_EXTENSIONS.has(extension)) {
6449
- for (const jsExtension of Resolver.JS_EXTENSIONS) {
6450
- const candidate = replaceExtension(filePath, jsExtension);
6451
- if (Resolver.isFile(candidate)) {
6452
- this.files.add(candidate);
6453
- return candidate;
6454
- }
6455
- }
6456
- return;
6457
- }
6458
- }
6459
- };
6460
-
6461
6508
  //#endregion
6462
6509
  //#region src/main.ts
6463
6510
  var App = class {