@sillsdev/docu-notion 1.0.0-alpha.6 → 1.0.0-alpha.7

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.
@@ -6,8 +6,26 @@ exports.gifEmbed = {
6
6
  regexMarkdownModifications: [
7
7
  {
8
8
  // I once saw a gif coming from Notion that wasn't a full
9
- // url, which wouldn't work, hence the "http" requirement
10
- regex: /\[.*?\]\((http.*?(\.(gif|GIF)))\)/,
9
+ // url, which wouldn't work, hence the "http" requirement.
10
+ //
11
+ // We only embed when the link's text is an AUTO-GENERATED label, not
12
+ // something the author typed. By the time this regex runs the label can
13
+ // take three auto shapes:
14
+ // - empty `[]` (an embed)
15
+ // - the literal `[bookmark]` placeholder notion-to-md emits for
16
+ // bookmark blocks (seen when standardExternalLinkConversion isn't in
17
+ // the config, e.g. the unit tests)
18
+ // - the URL repeated as the label, `[http...gif](http...gif)`, which is
19
+ // what standardExternalLinkConversion rewrites `[bookmark]` into in
20
+ // the production config (it runs in an earlier phase, see transform.ts)
21
+ // A link the author gave real text, e.g. `[see animation](...gif)`, is
22
+ // none of these, so it's left as a clickable link rather than turned into
23
+ // an image (which would also throw the text away).
24
+ //
25
+ // The optional leading "!" lets us match (and replace) a link that
26
+ // another mod has already turned into an image, instead of prepending
27
+ // a second "!" and producing "!![](...)".
28
+ regex: /!?\[(?:bookmark|https?:\/\/[^\]]*\.(?:gif|GIF)[^\]]*)?\]\((http.*?(\.(gif|GIF)))\)/,
11
29
  replacementPattern: `![]($1)`,
12
30
  },
13
31
  ],
@@ -16,7 +34,14 @@ exports.imgurGifEmbed = {
16
34
  name: "imgur",
17
35
  regexMarkdownModifications: [
18
36
  {
19
- regex: /\[.*?\]\((.*?imgur\.com\/.*?)\)/, // imgur.com
37
+ // Only embed links whose text is an auto-generated label (empty `[]`,
38
+ // `[bookmark]`, or the URL repeated as the label `[http...imgur.com/...]`),
39
+ // so that a link the author gave real text to is kept as a clickable link
40
+ // rather than converted to an image. See the longer note in gifEmbed above
41
+ // for why all three label shapes can occur here.
42
+ // The optional leading "!" lets us match a link that's already an image
43
+ // without prepending a second "!".
44
+ regex: /!?\[(?:bookmark|https?:\/\/[^\]]*imgur\.com\/[^\]]*)?\]\((.*?imgur\.com\/.*?)\)/, // imgur.com
20
45
  // imgur links to gifs need a .gif at the end, but the url they give you doesn't have one.
21
46
  replacementPattern: `![]($1.gif)`,
22
47
  },
@@ -8,10 +8,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const log_1 = require("../log");
13
16
  const pluginTestRun_1 = require("./pluginTestRun");
14
17
  const embedTweaks_1 = require("./embedTweaks");
18
+ const externalLinks_1 = require("./externalLinks");
19
+ const default_docunotion_config_1 = __importDefault(require("../config/default.docunotion.config"));
20
+ function paragraph(text) {
21
+ return {
22
+ type: "paragraph",
23
+ paragraph: {
24
+ rich_text: [
25
+ {
26
+ type: "text",
27
+ text: { content: text, link: null },
28
+ annotations: {
29
+ bold: false,
30
+ italic: false,
31
+ strikethrough: false,
32
+ underline: false,
33
+ code: false,
34
+ color: "default",
35
+ },
36
+ plain_text: text,
37
+ href: null,
38
+ },
39
+ ],
40
+ },
41
+ };
42
+ }
15
43
  test("imgur", () => __awaiter(void 0, void 0, void 0, function* () {
16
44
  (0, log_1.setLogLevel)("verbose");
17
45
  const config = { plugins: [embedTweaks_1.imgurGifEmbed] };
@@ -25,6 +53,93 @@ test("imgur", () => __awaiter(void 0, void 0, void 0, function* () {
25
53
  ]);
26
54
  expect(result.trim()).toBe(`![](https://imgur.com/gallery/U8TTNuI.gif)`);
27
55
  }));
56
+ // Regression test for the "!![](...)" bug: with both plugins active (the
57
+ // default config order), the imgur mod turns a bare imgur link into an image,
58
+ // then the gif mod sees that ".gif" image and must not prepend a second "!".
59
+ test("imgur + gif together produce a single leading bang", () => __awaiter(void 0, void 0, void 0, function* () {
60
+ (0, log_1.setLogLevel)("verbose");
61
+ const config = { plugins: [embedTweaks_1.imgurGifEmbed, embedTweaks_1.gifEmbed] };
62
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(config, [
63
+ {
64
+ object: "block",
65
+ id: "e36710d8-98ad-40dc-b41b-b376ebdd6894",
66
+ type: "bookmark",
67
+ bookmark: { caption: [], url: "https://imgur.com/E83qLj6" },
68
+ },
69
+ ]);
70
+ expect(result.trim()).toBe(`![](https://imgur.com/E83qLj6.gif)`);
71
+ expect(result).not.toContain("!![]");
72
+ }));
73
+ // An inline link the user gave real text to must stay a clickable link: we must
74
+ // not turn it into an image (which also discards the text). Uses the default
75
+ // config order so both mods get a crack at it.
76
+ test("imgur link with author text is left as a clickable link", () => __awaiter(void 0, void 0, void 0, function* () {
77
+ (0, log_1.setLogLevel)("verbose");
78
+ const config = { plugins: [embedTweaks_1.imgurGifEmbed, embedTweaks_1.gifEmbed] };
79
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(config, [
80
+ paragraph("all at once ([see animation](https://imgur.com/gcrxl5k))."),
81
+ paragraph("(See an animation of these [new overlay features](https://imgur.com/E83qLj6))"),
82
+ ]);
83
+ expect(result).toContain("[see animation](https://imgur.com/gcrxl5k)");
84
+ expect(result).toContain("[new overlay features](https://imgur.com/E83qLj6)");
85
+ // nothing should have been turned into an image
86
+ expect(result).not.toContain("![]");
87
+ expect(result).not.toContain(".gif");
88
+ }));
89
+ // Production-realistic: standardExternalLinkConversion runs in an earlier phase
90
+ // and rewrites a Notion `[bookmark](url)` into `[url](url)` before the embed
91
+ // regexes run. The embed must still recognize that as an auto-label and embed it.
92
+ test("imgur bookmark still embeds after external-link conversion", () => __awaiter(void 0, void 0, void 0, function* () {
93
+ (0, log_1.setLogLevel)("verbose");
94
+ const config = {
95
+ plugins: [externalLinks_1.standardExternalLinkConversion, embedTweaks_1.imgurGifEmbed, embedTweaks_1.gifEmbed],
96
+ };
97
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(config, [
98
+ {
99
+ object: "block",
100
+ id: "e36710d8-98ad-40dc-b41b-b376ebdd6894",
101
+ type: "bookmark",
102
+ bookmark: { caption: [], url: "https://imgur.com/gallery/U8TTNuI" },
103
+ },
104
+ ]);
105
+ expect(result.trim()).toBe(`![](https://imgur.com/gallery/U8TTNuI.gif)`);
106
+ expect(result).not.toContain("!![]");
107
+ }));
108
+ // ...but an authored inline link must survive that same pipeline as a link.
109
+ test("authored imgur link survives external-link conversion as a link", () => __awaiter(void 0, void 0, void 0, function* () {
110
+ (0, log_1.setLogLevel)("verbose");
111
+ const config = {
112
+ plugins: [externalLinks_1.standardExternalLinkConversion, embedTweaks_1.imgurGifEmbed, embedTweaks_1.gifEmbed],
113
+ };
114
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(config, [
115
+ paragraph("all at once ([see animation](https://imgur.com/gcrxl5k))."),
116
+ ]);
117
+ expect(result).toContain("[see animation](https://imgur.com/gcrxl5k)");
118
+ expect(result).not.toContain("![]");
119
+ expect(result).not.toContain(".gif");
120
+ }));
121
+ // Strongest guard: run the ACTUAL default production config (full plugin set
122
+ // and order) rather than a hand-picked subset, so future config drift (plugin
123
+ // reordering, the external-link converter changing) can't silently reopen the
124
+ // bug. A Notion bookmark to imgur must embed; an authored inline link must stay
125
+ // a clickable link.
126
+ test("default production config: bookmark embeds, authored link stays a link", () => __awaiter(void 0, void 0, void 0, function* () {
127
+ (0, log_1.setLogLevel)("verbose");
128
+ const result = yield (0, pluginTestRun_1.blocksToMarkdown)(default_docunotion_config_1.default, [
129
+ {
130
+ object: "block",
131
+ id: "e36710d8-98ad-40dc-b41b-b376ebdd6894",
132
+ type: "bookmark",
133
+ bookmark: { caption: [], url: "https://imgur.com/gallery/U8TTNuI" },
134
+ },
135
+ paragraph("all at once ([see animation](https://imgur.com/gcrxl5k))."),
136
+ ]);
137
+ // the bookmark became an embedded gif...
138
+ expect(result).toContain("![](https://imgur.com/gallery/U8TTNuI.gif)");
139
+ expect(result).not.toContain("!![]");
140
+ // ...while the authored link is untouched
141
+ expect(result).toContain("[see animation](https://imgur.com/gcrxl5k)");
142
+ }));
28
143
  test("gif", () => __awaiter(void 0, void 0, void 0, function* () {
29
144
  (0, log_1.setLogLevel)("verbose");
30
145
  const config = { plugins: [embedTweaks_1.gifEmbed] };
package/package.json CHANGED
@@ -98,5 +98,5 @@
98
98
  "esbuild@0.17.17": true,
99
99
  "fsevents": false
100
100
  },
101
- "version": "1.0.0-alpha.6"
101
+ "version": "1.0.0-alpha.7"
102
102
  }