@blankdotpage/cake 0.1.56 → 0.1.57

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 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/link/link.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AA2F3D,8CAA8C;AAC9C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,kCAAkC;AAClC,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAE9E,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,UAAU,KACf,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAkcF,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;AACvE,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAAC"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../../src/cake/extensions/link/link.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAwJ3D,8CAA8C;AAC9C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,kCAAkC;AAClC,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,aAAa,GAAG,iBAAiB,CAAC;AAE9E,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,UAAU,KACf,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAibF,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;AACvE,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAAC"}
@@ -37,6 +37,47 @@ function countBoundaryWrappers(fragment) {
37
37
  }
38
38
  return count;
39
39
  }
40
+ function findSimpleLinkRangeFromStart(source, linkStart) {
41
+ if (source[linkStart] !== "[") {
42
+ return null;
43
+ }
44
+ // Don't match image syntax ![...](...)
45
+ if (linkStart > 0 && source[linkStart - 1] === "!") {
46
+ return null;
47
+ }
48
+ let labelClose = -1;
49
+ for (let i = linkStart + 1; i < source.length; i += 1) {
50
+ const char = source[i];
51
+ if (char === "\\") {
52
+ i += 1;
53
+ continue;
54
+ }
55
+ // Nested labels are not supported by this parser.
56
+ if (char === "[") {
57
+ return null;
58
+ }
59
+ if (char === "]") {
60
+ labelClose = i;
61
+ break;
62
+ }
63
+ }
64
+ if (labelClose === -1) {
65
+ return null;
66
+ }
67
+ if (source[labelClose + 1] !== "(") {
68
+ return null;
69
+ }
70
+ const urlClose = source.indexOf(")", labelClose + 2);
71
+ if (urlClose === -1) {
72
+ return null;
73
+ }
74
+ return {
75
+ linkStart,
76
+ labelStart: linkStart + 1,
77
+ labelEnd: labelClose,
78
+ urlClose,
79
+ };
80
+ }
40
81
  function findEnclosingLinkRange(source, from, to) {
41
82
  if (source.length === 0) {
42
83
  return null;
@@ -46,29 +87,39 @@ function findEnclosingLinkRange(source, from, to) {
46
87
  if (start >= end) {
47
88
  return null;
48
89
  }
49
- let linkStart = source.lastIndexOf("[", start);
50
- while (linkStart !== -1) {
51
- // Skip image syntax ![...](...)
52
- if (linkStart > 0 && source[linkStart - 1] === "!") {
53
- linkStart = source.lastIndexOf("[", linkStart - 1);
54
- continue;
90
+ let cursor = 0;
91
+ while (cursor < source.length) {
92
+ const linkStart = source.indexOf("[", cursor);
93
+ if (linkStart === -1) {
94
+ break;
55
95
  }
56
- const labelClose = source.indexOf("](", linkStart + 1);
57
- if (labelClose === -1) {
58
- linkStart = source.lastIndexOf("[", linkStart - 1);
96
+ const range = findSimpleLinkRangeFromStart(source, linkStart);
97
+ if (!range) {
98
+ cursor = linkStart + 1;
59
99
  continue;
60
100
  }
61
- const urlClose = source.indexOf(")", labelClose + 2);
62
- if (urlClose === -1) {
63
- linkStart = source.lastIndexOf("[", linkStart - 1);
64
- continue;
101
+ if (range.labelStart <= start && end <= range.labelEnd) {
102
+ return range;
65
103
  }
66
- const labelStart = linkStart + 1;
67
- const labelEnd = labelClose;
68
- if (labelStart <= start && end <= labelEnd) {
69
- return { linkStart, labelStart, labelEnd, urlClose };
104
+ cursor = range.urlClose + 1;
105
+ }
106
+ return null;
107
+ }
108
+ function findLinkRangeByScanningBackward(source, startPos) {
109
+ if (source.length === 0) {
110
+ return null;
111
+ }
112
+ let searchFrom = Math.min(Math.max(0, startPos), source.length - 1);
113
+ while (searchFrom >= 0) {
114
+ const linkStart = source.lastIndexOf("[", searchFrom);
115
+ if (linkStart === -1) {
116
+ return null;
70
117
  }
71
- linkStart = source.lastIndexOf("[", linkStart - 1);
118
+ const range = findSimpleLinkRangeFromStart(source, linkStart);
119
+ if (range) {
120
+ return range;
121
+ }
122
+ searchFrom = linkStart - 1;
72
123
  }
73
124
  return null;
74
125
  }
@@ -154,35 +205,28 @@ function installLinkExtension(editor, options) {
154
205
  ]));
155
206
  disposers.push(editor.registerOnEdit((command, state) => {
156
207
  if (command.type === "unlink") {
157
- // Find the link at the given cursor position and remove the link markup
158
- const cursorPos = command.start;
159
- const sourcePos = state.map.cursorToSource(cursorPos, "forward");
208
+ // Find the link around the given selection and remove link markup.
209
+ const cursorStart = Math.min(command.start, command.end);
210
+ const cursorEnd = Math.max(command.start, command.end);
211
+ const sourceStart = state.map.cursorToSource(cursorStart, "forward");
212
+ const sourceEnd = state.map.cursorToSource(cursorEnd, "backward");
213
+ const from = Math.min(sourceStart, sourceEnd);
214
+ const to = Math.max(from + 1, sourceEnd);
160
215
  const source = state.source;
161
- // Search backwards for the opening bracket
162
- let linkStart = sourcePos;
163
- while (linkStart > 0 && source[linkStart] !== "[") {
164
- linkStart--;
165
- }
166
- if (source[linkStart] !== "[") {
167
- return null;
168
- }
169
- // Find the ]( separator
170
- const labelClose = source.indexOf("](", linkStart + 1);
171
- if (labelClose === -1) {
172
- return null;
173
- }
174
- // Find the closing )
175
- const urlClose = source.indexOf(")", labelClose + 2);
176
- if (urlClose === -1) {
216
+ const existingLink = findEnclosingLinkRange(source, from, to) ??
217
+ findLinkRangeByScanningBackward(source, from);
218
+ if (!existingLink) {
177
219
  return null;
178
220
  }
179
221
  // Extract the label (text between [ and ]( )
180
- const label = source.slice(linkStart + 1, labelClose);
222
+ const label = source.slice(existingLink.labelStart, existingLink.labelEnd);
181
223
  // Replace [label](url) with just label
182
- const nextSource = source.slice(0, linkStart) + label + source.slice(urlClose + 1);
224
+ const nextSource = source.slice(0, existingLink.linkStart) +
225
+ label +
226
+ source.slice(existingLink.urlClose + 1);
183
227
  // Calculate new cursor position - place it at the end of the label
184
228
  const newState = state.runtime.createState(nextSource);
185
- const labelEndSource = linkStart + label.length;
229
+ const labelEndSource = existingLink.linkStart + label.length;
186
230
  const newCursor = newState.map.sourceToCursor(labelEndSource, "forward");
187
231
  return {
188
232
  source: nextSource,
@@ -194,34 +238,25 @@ function installLinkExtension(editor, options) {
194
238
  };
195
239
  }
196
240
  if (command.type === "set-link-url") {
197
- const cursorPos = Math.min(command.start, command.end);
198
- const sourcePos = state.map.cursorToSource(cursorPos, "forward");
241
+ const cursorStart = Math.min(command.start, command.end);
242
+ const cursorEnd = Math.max(command.start, command.end);
243
+ const sourceStart = state.map.cursorToSource(cursorStart, "forward");
244
+ const sourceEnd = state.map.cursorToSource(cursorEnd, "backward");
245
+ const from = Math.min(sourceStart, sourceEnd);
246
+ const to = Math.max(from + 1, sourceEnd);
199
247
  const source = state.source;
200
- // Search backwards for the opening bracket
201
- let linkStart = sourcePos;
202
- while (linkStart > 0 && source[linkStart] !== "[") {
203
- linkStart--;
204
- }
205
- if (source[linkStart] !== "[") {
206
- return null;
207
- }
208
- // Find the ]( separator
209
- const labelClose = source.indexOf("](", linkStart + 1);
210
- if (labelClose === -1) {
211
- return null;
212
- }
213
- // Find the closing )
214
- const urlClose = source.indexOf(")", labelClose + 2);
215
- if (urlClose === -1) {
248
+ const existingLink = findEnclosingLinkRange(source, from, to) ??
249
+ findLinkRangeByScanningBackward(source, from);
250
+ if (!existingLink) {
216
251
  return null;
217
252
  }
218
- const nextSource = source.slice(0, labelClose + 2) +
253
+ const nextSource = source.slice(0, existingLink.labelEnd + 2) +
219
254
  command.url +
220
- source.slice(urlClose);
255
+ source.slice(existingLink.urlClose);
221
256
  const nextState = state.runtime.createState(nextSource);
222
257
  if (command.selectLabel) {
223
- const labelStartSource = linkStart + 1;
224
- const labelEndSource = labelClose;
258
+ const labelStartSource = existingLink.labelStart;
259
+ const labelEndSource = existingLink.labelEnd;
225
260
  const startCursor = nextState.map.sourceToCursor(labelStartSource, "forward");
226
261
  const endCursor = nextState.map.sourceToCursor(labelEndSource, "backward");
227
262
  return {
@@ -233,7 +268,7 @@ function installLinkExtension(editor, options) {
233
268
  },
234
269
  };
235
270
  }
236
- const endCursor = nextState.map.sourceToCursor(labelClose, "backward");
271
+ const endCursor = nextState.map.sourceToCursor(existingLink.labelEnd, "backward");
237
272
  return {
238
273
  source: nextSource,
239
274
  selection: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blankdotpage/cake",
3
- "version": "0.1.56",
3
+ "version": "0.1.57",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",