@staticbolt/core 1.0.0-beta.10 → 1.0.0-beta.12

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();
@@ -1583,20 +1547,6 @@ async function loadPrettier(filePath) {
1583
1547
  }
1584
1548
  }
1585
1549
 
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
1550
  //#endregion
1601
1551
  //#region src/plugins/i18n/get-locales.ts
1602
1552
  function getLocals(options) {
@@ -3067,6 +3017,28 @@ function htmlBuildTimeScript(options = {}) {
3067
3017
  }
3068
3018
  for (const node of metadata.ast.querySelectorAll(query)) node.remove();
3069
3019
  }
3020
+ },
3021
+ lspHtmlData() {
3022
+ return {
3023
+ version: 1.1,
3024
+ tags: [{
3025
+ name: "script",
3026
+ attributes: [
3027
+ {
3028
+ name: buildAttribute,
3029
+ description: "This attribute is used to mark the script as build-time script."
3030
+ },
3031
+ {
3032
+ name: fullDomAttribute,
3033
+ description: "Opt into a full DOM context using `jsdom`. When not present, the lighter `@staticbolt/node-html-parser` is used instead."
3034
+ },
3035
+ {
3036
+ name: contextAttribute,
3037
+ description: "Pass global context object as JSON to be available in the script during execution."
3038
+ }
3039
+ ]
3040
+ }]
3041
+ };
3070
3042
  }
3071
3043
  };
3072
3044
  }
@@ -3249,6 +3221,8 @@ function htmlBundleScriptPlugin(options = {}) {
3249
3221
  node.textContent = "";
3250
3222
  if (this.findMetadata({ filePath: outfile })) {
3251
3223
  this.log.info(`The entry point "${entryPoint}" is already bundled in "${outfile}", skipping...`);
3224
+ if (scriptMetadataID) metadata.scriptsMetadataList.delete(scriptMetadataID);
3225
+ node.setAttribute("src", relative(dirname(filePath), outfile));
3252
3226
  continue;
3253
3227
  }
3254
3228
  entryPoint = outfile;
@@ -3324,6 +3298,32 @@ function htmlBundleScriptPlugin(options = {}) {
3324
3298
  node.textContent = "";
3325
3299
  this.addMetadata(newScriptMetadata);
3326
3300
  }
3301
+ },
3302
+ lspHtmlData() {
3303
+ return {
3304
+ version: 1.1,
3305
+ tags: [{
3306
+ name: "script",
3307
+ attributes: [
3308
+ {
3309
+ name: bundleAttribute,
3310
+ description: "Enable script bundling."
3311
+ },
3312
+ {
3313
+ name: bundleOutAttribute,
3314
+ 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."
3315
+ },
3316
+ {
3317
+ name: externalsAttribute,
3318
+ description: `Glob patterns list to treat as external during bundling. (semicolon-separated)\n\nDefaults to "${defaultExternal.join(";")}".`
3319
+ },
3320
+ {
3321
+ name: externalsExcludeAttribute,
3322
+ description: `Glob patterns that exempt files from being treated as external, even if they match \`externals\`. (semicolon-separated)\n\nDefaults to "${defaultExternalExclude.join(";")}".`
3323
+ }
3324
+ ]
3325
+ }]
3326
+ };
3327
3327
  }
3328
3328
  };
3329
3329
  }
@@ -3393,6 +3393,24 @@ function htmlBundleStylePlugin(options = {}) {
3393
3393
  continue;
3394
3394
  }
3395
3395
  }
3396
+ },
3397
+ lspHtmlData() {
3398
+ return {
3399
+ version: 1.1,
3400
+ tags: [{
3401
+ name: "link",
3402
+ attributes: [{
3403
+ name: bundleAttribute,
3404
+ description: "Enable style bundling."
3405
+ }]
3406
+ }, {
3407
+ name: "style",
3408
+ attributes: [{
3409
+ name: bundleAttribute,
3410
+ description: "Enable style bundling."
3411
+ }]
3412
+ }]
3413
+ };
3396
3414
  }
3397
3415
  };
3398
3416
  }
@@ -3407,6 +3425,16 @@ function htmlFragmentPlugin(options = {}) {
3407
3425
  if (!isHtmlMetadata(metadata)) return;
3408
3426
  const elements = metadata.ast.querySelectorAll(tag);
3409
3427
  for (const node of elements) node.replaceWith(node.innerHTML.trim());
3428
+ },
3429
+ lspHtmlData() {
3430
+ return {
3431
+ version: 1.1,
3432
+ tags: [{
3433
+ name: tag,
3434
+ description: "At build time, this tag is replaced with its contents.",
3435
+ attributes: []
3436
+ }]
3437
+ };
3410
3438
  }
3411
3439
  };
3412
3440
  }
@@ -3502,6 +3530,18 @@ function htmlIifeScriptPlugin(options = {}) {
3502
3530
  continue;
3503
3531
  }
3504
3532
  }
3533
+ },
3534
+ lspHtmlData() {
3535
+ return {
3536
+ version: 1.1,
3537
+ tags: [{
3538
+ name: "script",
3539
+ attributes: [{
3540
+ name: iifeAttribute,
3541
+ description: "Enabling this will wrap the script content in an IIFE (Immediately Invoked Function Expression).\n\nWorks only with inline global scripts."
3542
+ }]
3543
+ }]
3544
+ };
3505
3545
  }
3506
3546
  };
3507
3547
  }
@@ -3548,6 +3588,18 @@ function htmlInlineScriptPlugin(options = {}) {
3548
3588
  metadata.scriptsMetadataList.set(metadataID, scriptMetadataClone);
3549
3589
  scriptTag.removeAttribute("src");
3550
3590
  }
3591
+ },
3592
+ lspHtmlData() {
3593
+ return {
3594
+ version: 1.1,
3595
+ tags: [{
3596
+ name: "script",
3597
+ attributes: [{
3598
+ name: inlineAttribute,
3599
+ description: "Enable inlining external scripts directly into the HTML at build time. It supports local files, remote URLs."
3600
+ }]
3601
+ }]
3602
+ };
3551
3603
  }
3552
3604
  };
3553
3605
  }
@@ -3613,6 +3665,18 @@ function htmlInlineStylePlugin(options = {}) {
3613
3665
  const attributesString = Object.entries(linkTag.attrs).map(([name, value]) => `${name}="${value}"`).join(" ");
3614
3666
  linkTag.replaceWith(`<style ${attributesString}></style>`);
3615
3667
  }
3668
+ },
3669
+ lspHtmlData() {
3670
+ return {
3671
+ version: 1.1,
3672
+ tags: [{
3673
+ name: "link",
3674
+ attributes: [{
3675
+ name: inlineAttribute,
3676
+ description: "Enable inlining external stylesheets directly into the HTML at build time. It supports both local files and remote URLs."
3677
+ }]
3678
+ }]
3679
+ };
3616
3680
  }
3617
3681
  };
3618
3682
  }
@@ -3687,6 +3751,18 @@ function HtmlInlineSvgPlugin(options = {}) {
3687
3751
  for (const [attribute, value] of Object.entries(node.attrs)) svgElement.setAttribute(attribute, value);
3688
3752
  node.replaceWith(svgElement);
3689
3753
  }
3754
+ },
3755
+ lspHtmlData() {
3756
+ return {
3757
+ version: 1.1,
3758
+ tags: [{
3759
+ name: "svg",
3760
+ attributes: [{
3761
+ name: inlineAttribute,
3762
+ description: "Enable inlining external SVGs directly into the HTML at build time. It supports both local files and remote URLs."
3763
+ }]
3764
+ }]
3765
+ };
3690
3766
  }
3691
3767
  };
3692
3768
  }
@@ -3785,6 +3861,22 @@ function htmlInlineTextPlugin(options = {}) {
3785
3861
  const importers = deps.getImporters(id);
3786
3862
  for (const importer of importers) compileSet.add(importer);
3787
3863
  }
3864
+ },
3865
+ lspHtmlData() {
3866
+ return {
3867
+ version: 1.1,
3868
+ tags: [{
3869
+ name: tag,
3870
+ description: "At build time, this tag is replaced with the contents of the external text file.",
3871
+ attributes: [{
3872
+ name: sourceAttribute,
3873
+ description: "The path to the external text file."
3874
+ }, {
3875
+ name: noEscapeAttribute,
3876
+ description: "Disable HTML escaping."
3877
+ }]
3878
+ }]
3879
+ };
3788
3880
  }
3789
3881
  };
3790
3882
  }
@@ -3843,6 +3935,35 @@ function htmlInsertPlugin(options = {}) {
3843
3935
  filePath: metadata.id
3844
3936
  });
3845
3937
  }
3938
+ },
3939
+ lspHtmlData() {
3940
+ return {
3941
+ version: 1.1,
3942
+ tags: [{
3943
+ name: tag,
3944
+ description: "At build time, inject HTML content into any target element on the page using a CSS selector at build time.",
3945
+ attributes: [
3946
+ {
3947
+ name: selectorAttribute,
3948
+ description: "The CSS selector of the target element."
3949
+ },
3950
+ {
3951
+ name: replaceAttribute,
3952
+ description: "Replace the target element with the contents of the custom insert element."
3953
+ },
3954
+ {
3955
+ name: whereAttribute,
3956
+ description: "The position of the inserted element.",
3957
+ values: [
3958
+ { name: "beforebegin" },
3959
+ { name: "afterbegin" },
3960
+ { name: "beforeend" },
3961
+ { name: "afterend" }
3962
+ ]
3963
+ }
3964
+ ]
3965
+ }]
3966
+ };
3846
3967
  }
3847
3968
  };
3848
3969
  }
@@ -3890,14 +4011,14 @@ function executeExpression$1(expressionString, data) {
3890
4011
  //#endregion
3891
4012
  //#region src/plugins/html-layout/html-layout-plugin.ts
3892
4013
  function htmlLayoutPlugin(options = {}) {
3893
- const tags = options.tags ?? ["layout", "part"];
4014
+ const layoutTags = options.tags ?? ["layout", "part"];
3894
4015
  const sourceAttribute = options.layoutSourceAttribute ?? "src";
3895
4016
  const dataSourceAttribute = options.dataSourceAttribute ?? "dataSource";
3896
4017
  const dataJsonAttribute = options.dataJsonAttribute ?? "dataJson";
3897
4018
  const alwaysIncludeAttribute = options.alwaysIncludeAttribute ?? "always-include";
3898
4019
  const addAttributeAttribute = options.addAttributeAttribute ?? "add-attr";
3899
4020
  const removeAttributeAttribute = options.removeAttributeAttribute ?? "remove-attr";
3900
- const query = tags.join(",");
4021
+ const query = layoutTags.join(",");
3901
4022
  const printFmtError = PrintFormattedError.create({ function: htmlLayoutPlugin });
3902
4023
  const htmlLayoutMetadataCache = [];
3903
4024
  /**
@@ -3907,12 +4028,12 @@ function htmlLayoutPlugin(options = {}) {
3907
4028
  const dataSourceCache = /* @__PURE__ */ new Map();
3908
4029
  function isLayoutPath(path) {
3909
4030
  const fileName = basename(path);
3910
- return tags.some((tag) => fileName.endsWith(`.${tag}.html`));
4031
+ return layoutTags.some((tag) => fileName.endsWith(`.${tag}.html`));
3911
4032
  }
3912
4033
  return {
3913
4034
  name: "html-layout",
3914
4035
  load(content, relativePath, { type }) {
3915
- if (type && !tags.includes(type)) return;
4036
+ if (type && !layoutTags.includes(type)) return;
3916
4037
  if (!isLayoutPath(relativePath)) return;
3917
4038
  const textAssetMetadata = {
3918
4039
  type: METADATA_TYPES.TextAsset,
@@ -3951,7 +4072,7 @@ function htmlLayoutPlugin(options = {}) {
3951
4072
  }
3952
4073
  if (isMarkdownMetadata(metadata)) for (const [key, source] of Object.entries(metadata.ast.frontmatter)) {
3953
4074
  if (!source) continue;
3954
- if (tags.includes(key) || key === dataSourceAttribute) sources.push({
4075
+ if (layoutTags.includes(key) || key === dataSourceAttribute) sources.push({
3955
4076
  get source() {
3956
4077
  return source;
3957
4078
  },
@@ -4176,7 +4297,7 @@ function htmlLayoutPlugin(options = {}) {
4176
4297
  return;
4177
4298
  }
4178
4299
  if (isMarkdownMetadata(metadata)) {
4179
- const tag = Object.keys(metadata.ast.frontmatter).find((key) => tags.includes(key));
4300
+ const tag = Object.keys(metadata.ast.frontmatter).find((key) => layoutTags.includes(key));
4180
4301
  if (!tag) return;
4181
4302
  let attributesString = "";
4182
4303
  for (const [key, value] of Object.entries(metadata.ast.frontmatter)) attributesString += `${key === tag ? sourceAttribute : key}="${value}" `;
@@ -4188,6 +4309,56 @@ function htmlLayoutPlugin(options = {}) {
4188
4309
  };
4189
4310
  return;
4190
4311
  }
4312
+ },
4313
+ lspHtmlData() {
4314
+ const attributes = [
4315
+ {
4316
+ name: sourceAttribute,
4317
+ description: "The path to the layout to use."
4318
+ },
4319
+ {
4320
+ name: dataSourceAttribute,
4321
+ description: "The path for a JSON file containing data for the layout."
4322
+ },
4323
+ {
4324
+ name: dataJsonAttribute,
4325
+ description: "The layout data in JSON format."
4326
+ }
4327
+ ];
4328
+ const alwaysInclude = {
4329
+ name: alwaysIncludeAttribute,
4330
+ 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."
4331
+ };
4332
+ const tags = [
4333
+ {
4334
+ name: "script",
4335
+ attributes: [alwaysInclude]
4336
+ },
4337
+ {
4338
+ name: "link",
4339
+ attributes: [alwaysInclude]
4340
+ },
4341
+ {
4342
+ name: "style",
4343
+ attributes: [alwaysInclude]
4344
+ }
4345
+ ];
4346
+ for (const tag of layoutTags) tags.push({
4347
+ name: tag,
4348
+ description: `This tag allows inlining a \`${tag}\` file.`,
4349
+ attributes
4350
+ });
4351
+ return {
4352
+ version: 1.1,
4353
+ tags,
4354
+ globalAttributes: [{
4355
+ name: addAttributeAttribute,
4356
+ 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."
4357
+ }, {
4358
+ name: removeAttributeAttribute,
4359
+ 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."
4360
+ }]
4361
+ };
4191
4362
  }
4192
4363
  };
4193
4364
  }
@@ -4255,7 +4426,22 @@ function htmlMarkdownPlugin(options = {}) {
4255
4426
  });
4256
4427
  continue;
4257
4428
  }
4258
- node.innerHTML = await markdownMetadata.ast.render();
4429
+ const asHtmlString = await markdownMetadata.ast.render();
4430
+ const htmlMetadata = await this.load(metadata.filePath, {
4431
+ code: asHtmlString,
4432
+ type: "html"
4433
+ });
4434
+ if (!isHtmlMetadata(htmlMetadata)) {
4435
+ printFmtError("Invalid HTML file:", metadata.filePath, {
4436
+ node,
4437
+ filePath: metadata.id
4438
+ });
4439
+ continue;
4440
+ }
4441
+ const metadataList = await this.resolveAndLoad(htmlMetadata);
4442
+ this.addMetadata(metadataList.slice(1));
4443
+ await this.transformAndSync(metadataList);
4444
+ node.set_content(htmlMetadata.ast.children);
4259
4445
  }
4260
4446
  const currentSources = /* @__PURE__ */ new Set();
4261
4447
  const markdowns = metadata.ast.querySelectorAll(markdownTag);
@@ -4279,8 +4465,23 @@ function htmlMarkdownPlugin(options = {}) {
4279
4465
  continue;
4280
4466
  }
4281
4467
  currentSources.add(sourceRelative);
4282
- const content = await markdownMetadata.ast.render();
4283
- node.replaceWith(content);
4468
+ const asHtmlString = await markdownMetadata.ast.render();
4469
+ const htmlMetadata = await this.load(sourceRelative, {
4470
+ code: asHtmlString,
4471
+ type: "html"
4472
+ });
4473
+ if (!isHtmlMetadata(htmlMetadata)) {
4474
+ printFmtError("Invalid HTML file:", sourceRelative, {
4475
+ node,
4476
+ filePath: metadata.id
4477
+ });
4478
+ continue;
4479
+ }
4480
+ const metadataList = await this.resolveAndLoad(htmlMetadata);
4481
+ this.addMetadata(metadataList.slice(1));
4482
+ await this.transformAndSync(metadataList);
4483
+ await this.rebase(htmlMetadata, join(this.root, metadata.filePath));
4484
+ node.replaceWith(...htmlMetadata.ast.children);
4284
4485
  }
4285
4486
  deps.update(metadata.id, currentSources);
4286
4487
  },
@@ -4293,6 +4494,23 @@ function htmlMarkdownPlugin(options = {}) {
4293
4494
  const importers = deps.getImporters(id);
4294
4495
  for (const importer of importers) compileSet.add(importer);
4295
4496
  }
4497
+ },
4498
+ lspHtmlData() {
4499
+ return {
4500
+ version: 1.1,
4501
+ globalAttributes: [{
4502
+ name: mdAttribute,
4503
+ description: "Render the contents of this element as markdown."
4504
+ }],
4505
+ tags: [{
4506
+ name: markdownTag,
4507
+ description: "This tag lets you render Markdown files inside HTML.",
4508
+ attributes: [{
4509
+ name: sourceAttribute,
4510
+ description: "The path to the external markdown file."
4511
+ }]
4512
+ }]
4513
+ };
4296
4514
  }
4297
4515
  };
4298
4516
  }
@@ -4898,8 +5116,8 @@ function getPreloadInfo(filePath) {
4898
5116
  //#region src/plugins/html-preload/html-preload-plugin.ts
4899
5117
  function htmlPreloadPlugin(options = {}) {
4900
5118
  const preloadAttribute = options.preloadAttribute ?? "preload";
4901
- const includeAttribute = options.includeAttribute ?? "include";
4902
- const excludeAttribute = options.excludeAttribute ?? "exclude";
5119
+ const includeAttribute = options.includeAttribute ?? "preload-include";
5120
+ const excludeAttribute = options.excludeAttribute ?? "preload-exclude";
4903
5121
  const asTypes = [
4904
5122
  "script",
4905
5123
  "style",
@@ -4978,6 +5196,37 @@ function htmlPreloadPlugin(options = {}) {
4978
5196
  head.insertAdjacentHTML("beforeend", linkTags.join("\n"));
4979
5197
  }
4980
5198
  }
5199
+ },
5200
+ lspHtmlData() {
5201
+ const attributes = [
5202
+ {
5203
+ name: preloadAttribute,
5204
+ description: `Enable preloading.
5205
+ Automatically generates \`<link rel="preload">\` tags for the dependencies of your scripts and stylesheets.
5206
+ This tells the browser to start fetching those files early, before they are discovered through normal parsing.
5207
+
5208
+ 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.`,
5209
+ values: asTypes.map((type) => ({ name: type }))
5210
+ },
5211
+ {
5212
+ name: includeAttribute,
5213
+ description: `Glob patterns list to include when using the \`${preloadAttribute}\` attribute. (semicolon-separated)`
5214
+ },
5215
+ {
5216
+ name: excludeAttribute,
5217
+ description: `Glob patterns list to exclude when using the \`${preloadAttribute}\` attribute. (semicolon-separated)`
5218
+ }
5219
+ ];
5220
+ return {
5221
+ version: 1.1,
5222
+ tags: [{
5223
+ name: "link",
5224
+ attributes
5225
+ }, {
5226
+ name: "script",
5227
+ attributes
5228
+ }]
5229
+ };
4981
5230
  }
4982
5231
  };
4983
5232
  }
@@ -6255,207 +6504,6 @@ function printExecutionTime(executionTime) {
6255
6504
  console.log();
6256
6505
  }
6257
6506
 
6258
- //#endregion
6259
- //#region src/resolver/get-aliases.ts
6260
- /** Gets path aliases from `tsconfig.json` */
6261
- function getPathAliases(root) {
6262
- const [tsconfig, tsconfigParseError] = readTsconfig(root);
6263
- if (tsconfigParseError !== null) return [null, tsconfigParseError];
6264
- const paths = tsconfig.paths ?? {};
6265
- const alias = {};
6266
- for (const key in paths) {
6267
- const aliasName = key.replace(/\*$/, "");
6268
- alias[aliasName] = paths[key][0].replace(/\*$/, "");
6269
- }
6270
- return [alias, null];
6271
- }
6272
- function readTsconfig(root) {
6273
- const [tsconfig, tsconfigParseError] = readJsonFile(join(root, "tsconfig.json"));
6274
- if (tsconfigParseError !== null) return [null, tsconfigParseError];
6275
- if (!tsconfig.compilerOptions) return [null, /* @__PURE__ */ new Error("[readTsconfig] No compilerOptions found in tsconfig.json")];
6276
- return [tsconfig.compilerOptions, null];
6277
- }
6278
-
6279
- //#endregion
6280
- //#region src/resolver/resolver.ts
6281
- const nodeModulesResolver = new ResolverFactory({
6282
- conditionNames: [
6283
- "browser",
6284
- "import",
6285
- "default"
6286
- ],
6287
- extensions: [
6288
- ".js",
6289
- ".json",
6290
- ".node",
6291
- ".css"
6292
- ],
6293
- symlinks: false
6294
- });
6295
- var Resolver = class Resolver {
6296
- root;
6297
- aliases = {};
6298
- notFound = /* @__PURE__ */ new Set();
6299
- files = /* @__PURE__ */ new Set();
6300
- directories = /* @__PURE__ */ new Set();
6301
- static JS_EXTENSIONS = new Set([
6302
- ".js",
6303
- ".mjs",
6304
- ".cjs",
6305
- ".jsx",
6306
- ".ts",
6307
- ".mts",
6308
- ".cts",
6309
- ".tsx"
6310
- ]);
6311
- static HTML_EXTENSIONS = new Set([".html", ".md"]);
6312
- constructor(root) {
6313
- this.root = root;
6314
- const [aliases] = getPathAliases(root);
6315
- if (aliases) this.aliases = aliases;
6316
- }
6317
- resolve(sourceOrLink, filePath) {
6318
- if (!isValidRelativePath(sourceOrLink)) return;
6319
- const absFilePath = isAbsolute(filePath) ? filePath : join(this.root, filePath);
6320
- const [source, suffix] = splitHtmlLink(sourceOrLink);
6321
- if (isAbsolute(source)) return;
6322
- const checkDirectory = suffix === "/";
6323
- const absSource = join(dirname(absFilePath), source);
6324
- const foundFile = this.findFile(absSource, checkDirectory);
6325
- if (foundFile) return {
6326
- path: foundFile,
6327
- exists: true,
6328
- suffix
6329
- };
6330
- const sourceForAlias = suffix === "/" ? source + "/" : source;
6331
- const resolvedPathAlias = Resolver.resolvePathAlias(sourceForAlias, this.aliases);
6332
- if (resolvedPathAlias) {
6333
- const absSource = join(this.root, resolvedPathAlias);
6334
- const foundFile = this.findFile(absSource, checkDirectory);
6335
- const isFileAlias = sourceForAlias in this.aliases && !sourceForAlias.endsWith("/");
6336
- if (!foundFile && !this.notFound.has(absSource.replace(/\/$/, ""))) {
6337
- this.notFound.add(absSource.replace(/\/$/, ""));
6338
- Log.warn(`[resolver] Source "${sourceOrLink}" found in "${filePath}" was resolved to "${resolvedPathAlias}", but the file is missing.`);
6339
- }
6340
- return {
6341
- path: foundFile ?? absSource,
6342
- exists: !!foundFile,
6343
- suffix,
6344
- isFileAlias,
6345
- isDirAlias: !isFileAlias
6346
- };
6347
- }
6348
- if (!source.startsWith(".")) {
6349
- const resolverResult = nodeModulesResolver.sync(this.root, source);
6350
- if (resolverResult.path) return {
6351
- path: resolverResult.path,
6352
- suffix,
6353
- exists: true,
6354
- isPackage: true
6355
- };
6356
- }
6357
- if (source.startsWith("./") || source.startsWith("../")) {
6358
- if (!this.notFound.has(absSource)) {
6359
- this.notFound.add(absSource);
6360
- Log.warn(`[resolver] Source "${sourceOrLink}" found in "${filePath}" points to a non-existent file.`);
6361
- }
6362
- return {
6363
- path: absSource,
6364
- suffix,
6365
- exists: false
6366
- };
6367
- }
6368
- }
6369
- resolveAlias(source) {
6370
- return Resolver.resolvePathAlias(source, this.aliases);
6371
- }
6372
- normalize(filePath) {
6373
- return normalize(filePath);
6374
- }
6375
- static isFile(filePath) {
6376
- try {
6377
- return statSync(filePath).isFile();
6378
- } catch (error) {
6379
- const code = error.code;
6380
- if (code === "ENOENT" || code === "ENOTDIR") return false;
6381
- throw error;
6382
- }
6383
- }
6384
- /** Aliased path to path */
6385
- static resolvePathAlias(filePath, aliases) {
6386
- for (const [key, value] of Object.entries(aliases)) {
6387
- if (key.endsWith("/")) {
6388
- if (!filePath.startsWith(key)) continue;
6389
- return filePath.replace(key, value);
6390
- }
6391
- if (filePath === key) return value;
6392
- }
6393
- }
6394
- /** Path to aliased path */
6395
- static resolveAliasPath(filePath, aliases) {
6396
- let shortest;
6397
- for (const [key, value] of Object.entries(aliases)) {
6398
- if (key.endsWith("/")) {
6399
- if (!filePath.startsWith(value)) continue;
6400
- const aliased = filePath.replace(value, key);
6401
- if (!shortest || aliased.length < shortest.length) shortest = aliased;
6402
- continue;
6403
- }
6404
- if (filePath === value && (!shortest || key.length < shortest.length)) shortest = key;
6405
- }
6406
- return shortest ?? filePath;
6407
- }
6408
- /** Path to aliased path */
6409
- aliasPath(filePath) {
6410
- return Resolver.resolveAliasPath(filePath, this.aliases);
6411
- }
6412
- findFile(filePath, checkDirectory = false) {
6413
- if (this.files.has(filePath)) return filePath;
6414
- if (Resolver.isFile(filePath)) {
6415
- this.files.add(filePath);
6416
- return filePath;
6417
- }
6418
- const extension = extname(filePath);
6419
- if (!extension) {
6420
- for (const candidateExtension of [...Resolver.JS_EXTENSIONS, ...Resolver.HTML_EXTENSIONS]) {
6421
- const candidate = replaceExtension(filePath, candidateExtension);
6422
- if (this.files.has(candidate)) return candidate;
6423
- if (Resolver.isFile(candidate)) {
6424
- this.files.add(candidate);
6425
- return candidate;
6426
- }
6427
- }
6428
- const withIndex = join(filePath, "index");
6429
- for (const candidateExtension of Resolver.HTML_EXTENSIONS) {
6430
- const candidate = replaceExtension(withIndex, candidateExtension);
6431
- if (this.files.has(candidate)) return candidate;
6432
- if (Resolver.isFile(candidate)) {
6433
- this.files.add(candidate);
6434
- return candidate;
6435
- }
6436
- }
6437
- if (checkDirectory) {
6438
- if (this.directories.has(filePath)) return filePath;
6439
- if (existsSync(filePath)) {
6440
- this.directories.add(filePath);
6441
- return filePath;
6442
- }
6443
- }
6444
- return;
6445
- }
6446
- if (Resolver.JS_EXTENSIONS.has(extension)) {
6447
- for (const jsExtension of Resolver.JS_EXTENSIONS) {
6448
- const candidate = replaceExtension(filePath, jsExtension);
6449
- if (Resolver.isFile(candidate)) {
6450
- this.files.add(candidate);
6451
- return candidate;
6452
- }
6453
- }
6454
- return;
6455
- }
6456
- }
6457
- };
6458
-
6459
6507
  //#endregion
6460
6508
  //#region src/main.ts
6461
6509
  var App = class {