@lvce-editor/editor-worker 16.2.0 → 16.4.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.
@@ -474,7 +474,7 @@ const getFirstEvent = (eventEmitter, eventMap) => {
474
474
  return promise;
475
475
  };
476
476
  const Message$1 = 3;
477
- const create$5$1 = async ({
477
+ const create$5$2 = async ({
478
478
  isMessagePortOpen,
479
479
  messagePort
480
480
  }) => {
@@ -525,7 +525,7 @@ const wrap$5 = messagePort => {
525
525
  };
526
526
  const IpcParentWithMessagePort$1 = {
527
527
  __proto__: null,
528
- create: create$5$1,
528
+ create: create$5$2,
529
529
  signal: signal$1,
530
530
  wrap: wrap$5
531
531
  };
@@ -731,7 +731,7 @@ const getErrorProperty = (error, prettyError) => {
731
731
  }
732
732
  };
733
733
  };
734
- const create$1$2 = (id, error) => {
734
+ const create$1$1 = (id, error) => {
735
735
  return {
736
736
  jsonrpc: Two$1,
737
737
  id,
@@ -742,7 +742,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
742
742
  const prettyError = preparePrettyError(error);
743
743
  logError(error, prettyError);
744
744
  const errorProperty = getErrorProperty(error, prettyError);
745
- return create$1$2(id, errorProperty);
745
+ return create$1$1(id, errorProperty);
746
746
  };
747
747
  const create$a = (message, result) => {
748
748
  return {
@@ -867,14 +867,14 @@ const execute$1 = (command, ...args) => {
867
867
  };
868
868
 
869
869
  const Two = '2.0';
870
- const create$s = (method, params) => {
870
+ const create$t = (method, params) => {
871
871
  return {
872
872
  jsonrpc: Two,
873
873
  method,
874
874
  params
875
875
  };
876
876
  };
877
- const create$r = (id, method, params) => {
877
+ const create$s = (id, method, params) => {
878
878
  const message = {
879
879
  id,
880
880
  jsonrpc: Two,
@@ -884,14 +884,14 @@ const create$r = (id, method, params) => {
884
884
  return message;
885
885
  };
886
886
  let id = 0;
887
- const create$q = () => {
887
+ const create$r = () => {
888
888
  return ++id;
889
889
  };
890
890
 
891
891
  /* eslint-disable n/no-unsupported-features/es-syntax */
892
892
 
893
893
  const registerPromise = map => {
894
- const id = create$q();
894
+ const id = create$r();
895
895
  const {
896
896
  promise,
897
897
  resolve
@@ -909,7 +909,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
909
909
  id,
910
910
  promise
911
911
  } = registerPromise(callbacks);
912
- const message = create$r(id, method, params);
912
+ const message = create$s(id, method, params);
913
913
  if (useSendAndTransfer && ipc.sendAndTransfer) {
914
914
  ipc.sendAndTransfer(message);
915
915
  } else {
@@ -945,7 +945,7 @@ const createRpc = ipc => {
945
945
  * @deprecated
946
946
  */
947
947
  send(method, ...params) {
948
- const message = create$s(method, params);
948
+ const message = create$t(method, params);
949
949
  ipc.send(message);
950
950
  }
951
951
  };
@@ -1011,13 +1011,13 @@ const createSharedLazyRpc = factory => {
1011
1011
  }
1012
1012
  };
1013
1013
  };
1014
- const create$i = async ({
1014
+ const create$j = async ({
1015
1015
  commandMap,
1016
1016
  isMessagePortOpen,
1017
1017
  send
1018
1018
  }) => {
1019
1019
  return createSharedLazyRpc(() => {
1020
- return create$2$1({
1020
+ return create$3$1({
1021
1021
  commandMap,
1022
1022
  isMessagePortOpen,
1023
1023
  send
@@ -1026,9 +1026,9 @@ const create$i = async ({
1026
1026
  };
1027
1027
  const LazyTransferMessagePortRpcParent = {
1028
1028
  __proto__: null,
1029
- create: create$i
1029
+ create: create$j
1030
1030
  };
1031
- const create$4$1 = async ({
1031
+ const create$5$1 = async ({
1032
1032
  commandMap,
1033
1033
  isMessagePortOpen = true,
1034
1034
  messagePort
@@ -1045,20 +1045,20 @@ const create$4$1 = async ({
1045
1045
  messagePort.start();
1046
1046
  return rpc;
1047
1047
  };
1048
- const create$3$1 = async ({
1048
+ const create$4$1 = async ({
1049
1049
  commandMap,
1050
1050
  messagePort
1051
1051
  }) => {
1052
- return create$4$1({
1052
+ return create$5$1({
1053
1053
  commandMap,
1054
1054
  messagePort
1055
1055
  });
1056
1056
  };
1057
1057
  const PlainMessagePortRpcParent = {
1058
1058
  __proto__: null,
1059
- create: create$3$1
1059
+ create: create$4$1
1060
1060
  };
1061
- const create$2$1 = async ({
1061
+ const create$3$1 = async ({
1062
1062
  commandMap,
1063
1063
  isMessagePortOpen,
1064
1064
  send
@@ -1068,7 +1068,7 @@ const create$2$1 = async ({
1068
1068
  port2
1069
1069
  } = new MessageChannel();
1070
1070
  await send(port1);
1071
- return create$4$1({
1071
+ return create$5$1({
1072
1072
  commandMap,
1073
1073
  isMessagePortOpen,
1074
1074
  messagePort: port2
@@ -1076,9 +1076,9 @@ const create$2$1 = async ({
1076
1076
  };
1077
1077
  const TransferMessagePortRpcParent = {
1078
1078
  __proto__: null,
1079
- create: create$2$1
1079
+ create: create$3$1
1080
1080
  };
1081
- const create$1$1 = async ({
1081
+ const create$2$1 = async ({
1082
1082
  commandMap
1083
1083
  }) => {
1084
1084
  // TODO create a commandMap per rpc instance
@@ -1090,7 +1090,7 @@ const create$1$1 = async ({
1090
1090
  };
1091
1091
  const WebWorkerRpcClient = {
1092
1092
  __proto__: null,
1093
- create: create$1$1
1093
+ create: create$2$1
1094
1094
  };
1095
1095
  const createMockRpc = ({
1096
1096
  commandMap
@@ -2619,6 +2619,108 @@ const getIncrementalEdits = async (oldState, newState) => {
2619
2619
  return emptyIncrementalEdits;
2620
2620
  };
2621
2621
 
2622
+ /**
2623
+ * Gets all regex matches for a given text and regex pattern
2624
+ * @param text The text to match against
2625
+ * @param regex The regex pattern to use (should have global flag)
2626
+ * @returns Array of regex matches
2627
+ */
2628
+ const getRegexMatches = (text, regex) => {
2629
+ return [...text.matchAll(regex)];
2630
+ };
2631
+
2632
+ // URL matching regex pattern - matches common URL schemes
2633
+ // Supports: http://, https://, ftp://, ftps://, file://
2634
+ // Also matches URLs without explicit scheme (www.example.com)
2635
+ const URL_PATTERN = /(?:(?:https?|ftp|ftps|file):\/\/)?(?:www\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?(?:\/[^\s]*)?/g;
2636
+
2637
+ // Regex to check if URL has a scheme (http://, https://, ftp://, etc.)
2638
+ const HAS_SCHEME_PATTERN = /^(?:https?|ftp|ftps|file):\/\//;
2639
+
2640
+ // Regex to check if URL starts with www.
2641
+ const HAS_WWW_PATTERN = /^www\./;
2642
+
2643
+ /**
2644
+ * Detects links in a given text and returns their positions
2645
+ * @param text The text to scan for links
2646
+ * @returns Array of links with their start position and length
2647
+ */
2648
+ const detectLinks = text => {
2649
+ const matches = getRegexMatches(text, URL_PATTERN);
2650
+ const links = [];
2651
+ for (const match of matches) {
2652
+ const url = match[0];
2653
+ // Only consider as link if it has a scheme or starts with www.
2654
+ if (HAS_SCHEME_PATTERN.test(url) || HAS_WWW_PATTERN.test(url)) {
2655
+ links.push({
2656
+ length: url.length,
2657
+ start: match.index ?? 0
2658
+ });
2659
+ }
2660
+ }
2661
+ return links;
2662
+ };
2663
+
2664
+ /**
2665
+ * Detects all links in an editor and returns them as decorations
2666
+ * @param editor The editor containing lines to scan
2667
+ * @returns Flat array of decorations in format [offset, length, type, modifiers, ...]
2668
+ */
2669
+ const detectAllLinksAsDecorations = editor => {
2670
+ const decorations = [];
2671
+ const {
2672
+ lines
2673
+ } = editor;
2674
+ let offset = 0;
2675
+ for (const line of lines) {
2676
+ const links = detectLinks(line);
2677
+ for (const link of links) {
2678
+ const linkOffset = offset + link.start;
2679
+ // Add link decoration: offset, length, type, modifiers
2680
+ decorations.push(linkOffset, link.length, Link, 0);
2681
+ }
2682
+ offset += line.length + 1; // +1 for newline
2683
+ }
2684
+ return decorations;
2685
+ };
2686
+
2687
+ /**
2688
+ * Gets the URL text at a given offset in the editor if it's a link
2689
+ * @param editor The editor
2690
+ * @param offset The offset in the document
2691
+ * @returns The URL string if the offset is on a link, or undefined
2692
+ */
2693
+ const getUrlAtOffset = (editor, offset) => {
2694
+ const {
2695
+ decorations,
2696
+ lines
2697
+ } = editor;
2698
+
2699
+ // Iterate through decorations in groups of 4 (offset, length, type, modifiers)
2700
+ for (let i = 0; i < decorations.length; i += 4) {
2701
+ const decorationOffset = decorations[i];
2702
+ const decorationLength = decorations[i + 1];
2703
+ const decorationType = decorations[i + 2];
2704
+
2705
+ // Check if this decoration is a link and if the offset falls within it
2706
+ if (decorationType === Link && offset >= decorationOffset && offset < decorationOffset + decorationLength) {
2707
+ // Extract the URL text from the editor content
2708
+ let currentOffset = 0;
2709
+ for (const line of lines) {
2710
+ const lineLength = line.length + 1; // +1 for newline
2711
+ if (currentOffset + lineLength > decorationOffset) {
2712
+ // The link starts in this line
2713
+ const linkStartInLine = decorationOffset - currentOffset;
2714
+ const url = line.slice(linkStartInLine, linkStartInLine + decorationLength);
2715
+ return url;
2716
+ }
2717
+ currentOffset += lineLength;
2718
+ }
2719
+ }
2720
+ }
2721
+ return undefined;
2722
+ };
2723
+
2622
2724
  const splitLines = lines => {
2623
2725
  if (!lines) {
2624
2726
  return [''];
@@ -3034,11 +3136,17 @@ const scheduleDocumentAndCursorsSelections = async (editor, changes, selectionCh
3034
3136
  selections: newSelections,
3035
3137
  undoStack: [...editor.undoStack, changes]
3036
3138
  };
3037
- set$6(editor.uid, editor, newEditor);
3038
- const incrementalEdits = await getIncrementalEdits(editor, newEditor);
3039
- const editorWithNewWidgets = await applyWidgetChanges(newEditor, changes);
3040
- const newEditor2 = {
3139
+ // Update link decorations after text changes
3140
+ const linkDecorations = detectAllLinksAsDecorations(newEditor);
3141
+ const newEditorWithDecorations = {
3041
3142
  ...newEditor,
3143
+ decorations: linkDecorations
3144
+ };
3145
+ set$6(editor.uid, editor, newEditorWithDecorations);
3146
+ const incrementalEdits = await getIncrementalEdits(editor, newEditorWithDecorations);
3147
+ const editorWithNewWidgets = await applyWidgetChanges(newEditorWithDecorations, changes);
3148
+ const newEditor2 = {
3149
+ ...newEditorWithDecorations,
3042
3150
  ...editorWithNewWidgets,
3043
3151
  incrementalEdits
3044
3152
  };
@@ -3308,108 +3416,6 @@ const getLanguages = async (platform, assetDir) => {
3308
3416
  return languages;
3309
3417
  };
3310
3418
 
3311
- /**
3312
- * Gets all regex matches for a given text and regex pattern
3313
- * @param text The text to match against
3314
- * @param regex The regex pattern to use (should have global flag)
3315
- * @returns Array of regex matches
3316
- */
3317
- const getRegexMatches = (text, regex) => {
3318
- return [...text.matchAll(regex)];
3319
- };
3320
-
3321
- // URL matching regex pattern - matches common URL schemes
3322
- // Supports: http://, https://, ftp://, ftps://, file://
3323
- // Also matches URLs without explicit scheme (www.example.com)
3324
- const URL_PATTERN = /(?:(?:https?|ftp|ftps|file):\/\/)?(?:www\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?(?:\/[^\s]*)?/g;
3325
-
3326
- // Regex to check if URL has a scheme (http://, https://, ftp://, etc.)
3327
- const HAS_SCHEME_PATTERN = /^(?:https?|ftp|ftps|file):\/\//;
3328
-
3329
- // Regex to check if URL starts with www.
3330
- const HAS_WWW_PATTERN = /^www\./;
3331
-
3332
- /**
3333
- * Detects links in a given text and returns their positions
3334
- * @param text The text to scan for links
3335
- * @returns Array of links with their start position and length
3336
- */
3337
- const detectLinks = text => {
3338
- const matches = getRegexMatches(text, URL_PATTERN);
3339
- const links = [];
3340
- for (const match of matches) {
3341
- const url = match[0];
3342
- // Only consider as link if it has a scheme or starts with www.
3343
- if (HAS_SCHEME_PATTERN.test(url) || HAS_WWW_PATTERN.test(url)) {
3344
- links.push({
3345
- length: url.length,
3346
- start: match.index ?? 0
3347
- });
3348
- }
3349
- }
3350
- return links;
3351
- };
3352
-
3353
- /**
3354
- * Detects all links in an editor and returns them as decorations
3355
- * @param editor The editor containing lines to scan
3356
- * @returns Flat array of decorations in format [offset, length, type, modifiers, ...]
3357
- */
3358
- const detectAllLinksAsDecorations = editor => {
3359
- const decorations = [];
3360
- const {
3361
- lines
3362
- } = editor;
3363
- let offset = 0;
3364
- for (const line of lines) {
3365
- const links = detectLinks(line);
3366
- for (const link of links) {
3367
- const linkOffset = offset + link.start;
3368
- // Add link decoration: offset, length, type, modifiers
3369
- decorations.push(linkOffset, link.length, Link, 0);
3370
- }
3371
- offset += line.length + 1; // +1 for newline
3372
- }
3373
- return decorations;
3374
- };
3375
-
3376
- /**
3377
- * Gets the URL text at a given offset in the editor if it's a link
3378
- * @param editor The editor
3379
- * @param offset The offset in the document
3380
- * @returns The URL string if the offset is on a link, or undefined
3381
- */
3382
- const getUrlAtOffset = (editor, offset) => {
3383
- const {
3384
- decorations,
3385
- lines
3386
- } = editor;
3387
-
3388
- // Iterate through decorations in groups of 4 (offset, length, type, modifiers)
3389
- for (let i = 0; i < decorations.length; i += 4) {
3390
- const decorationOffset = decorations[i];
3391
- const decorationLength = decorations[i + 1];
3392
- const decorationType = decorations[i + 2];
3393
-
3394
- // Check if this decoration is a link and if the offset falls within it
3395
- if (decorationType === Link && offset >= decorationOffset && offset < decorationOffset + decorationLength) {
3396
- // Extract the URL text from the editor content
3397
- let currentOffset = 0;
3398
- for (const line of lines) {
3399
- const lineLength = line.length + 1; // +1 for newline
3400
- if (currentOffset + lineLength > decorationOffset) {
3401
- // The link starts in this line
3402
- const linkStartInLine = decorationOffset - currentOffset;
3403
- const url = line.slice(linkStartInLine, linkStartInLine + decorationLength);
3404
- return url;
3405
- }
3406
- currentOffset += lineLength;
3407
- }
3408
- }
3409
- }
3410
- return undefined;
3411
- };
3412
-
3413
3419
  const measureCharacterWidth = async (fontWeight, fontSize, fontFamily, letterSpacing) => {
3414
3420
  return await measureTextWidth('a', fontWeight, fontSize, fontFamily, letterSpacing, false, 0);
3415
3421
  };
@@ -3497,6 +3503,37 @@ const getVisibleDiagnostics = async (editor, diagnostics) => {
3497
3503
  return visibleDiagnostics;
3498
3504
  };
3499
3505
 
3506
+ /**
3507
+ * Merges link decorations with diagnostic decorations
3508
+ * Links should always be present, but we also need to include any diagnostic decorations
3509
+ */
3510
+ const mergeLinksWithDiagnosticDecorations = (editor, diagnosticDecorations) => {
3511
+ // Get link decorations
3512
+ const linkDecorations = detectAllLinksAsDecorations(editor);
3513
+
3514
+ // Merge with diagnostic decorations
3515
+ const allDecorations = [...linkDecorations, ...diagnosticDecorations];
3516
+
3517
+ // Sort by offset to maintain proper order
3518
+ const sortedDecorations = [];
3519
+ for (let i = 0; i < allDecorations.length; i += 4) {
3520
+ sortedDecorations.push({
3521
+ length: allDecorations[i + 1],
3522
+ modifiers: allDecorations[i + 3],
3523
+ offset: allDecorations[i],
3524
+ type: allDecorations[i + 2]
3525
+ });
3526
+ }
3527
+ sortedDecorations.sort((a, b) => a.offset - b.offset);
3528
+
3529
+ // Flatten back to array format
3530
+ const result = [];
3531
+ for (const dec of sortedDecorations) {
3532
+ result.push(dec.offset, dec.length, dec.type, dec.modifiers);
3533
+ }
3534
+ return result;
3535
+ };
3536
+
3500
3537
  const updateDiagnostics = async newState => {
3501
3538
  try {
3502
3539
  // TODO handle error
@@ -3517,11 +3554,13 @@ const updateDiagnostics = async newState => {
3517
3554
  return newState;
3518
3555
  }
3519
3556
  const visualDecorations = await getVisibleDiagnostics(latest.newState, diagnostics);
3520
- // Re-detect link decorations after text changes
3521
- const linkDecorations = detectAllLinksAsDecorations(latest.newState);
3557
+ // Get diagnostic decorations from visual decorations (if any)
3558
+ const diagnosticDecorations = visualDecorations.flatMap(deco => [deco.offset, deco.length, deco.type, deco.modifiers || 0]);
3559
+ // Merge link decorations with diagnostic decorations
3560
+ const mergedDecorations = mergeLinksWithDiagnosticDecorations(latest.newState, diagnosticDecorations);
3522
3561
  const newEditor = {
3523
3562
  ...latest.newState,
3524
- decorations: linkDecorations,
3563
+ decorations: mergedDecorations,
3525
3564
  // Text-level decorations (flat array) for CSS classes
3526
3565
  diagnostics,
3527
3566
  visualDecorations // Visual decorations (objects with x, y, width, height) for squiggly underlines
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/editor-worker",
3
- "version": "16.2.0",
3
+ "version": "16.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git@github.com:lvce-editor/editor-worker.git"