@sillsdev/docu-notion 0.12.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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +135 -0
  3. package/dist/FlatGuidLayoutStrategy.d.ts +6 -0
  4. package/dist/FlatGuidLayoutStrategy.js +25 -0
  5. package/dist/HierarchicalNamedLayoutStrategy.d.ts +7 -0
  6. package/dist/HierarchicalNamedLayoutStrategy.js +80 -0
  7. package/dist/LayoutStrategy.d.ts +12 -0
  8. package/dist/LayoutStrategy.js +83 -0
  9. package/dist/MakeImagePersistencePlan.d.ts +2 -0
  10. package/dist/MakeImagePersistencePlan.js +66 -0
  11. package/dist/NotionImage-CaptionReading.spec.d.ts +1 -0
  12. package/dist/NotionImage-CaptionReading.spec.js +233 -0
  13. package/dist/NotionPage.d.ts +44 -0
  14. package/dist/NotionPage.js +194 -0
  15. package/dist/config/configuration.d.ts +5 -0
  16. package/dist/config/configuration.js +86 -0
  17. package/dist/config/default.docunotion.config.d.ts +3 -0
  18. package/dist/config/default.docunotion.config.js +37 -0
  19. package/dist/images.d.ts +24 -0
  20. package/dist/images.js +230 -0
  21. package/dist/index.d.ts +7 -0
  22. package/dist/index.js +37 -0
  23. package/dist/log.d.ts +11 -0
  24. package/dist/log.js +61 -0
  25. package/dist/makeImagePersistencePlan.spec.d.ts +1 -0
  26. package/dist/makeImagePersistencePlan.spec.js +35 -0
  27. package/dist/notion-styles.css +58 -0
  28. package/dist/plugins/CalloutTransformer.d.ts +24 -0
  29. package/dist/plugins/CalloutTransformer.js +88 -0
  30. package/dist/plugins/CalloutTransformer.spec.d.ts +1 -0
  31. package/dist/plugins/CalloutTransformer.spec.js +199 -0
  32. package/dist/plugins/ColumnListTransformer.d.ts +2 -0
  33. package/dist/plugins/ColumnListTransformer.js +34 -0
  34. package/dist/plugins/ColumnTransformer.d.ts +2 -0
  35. package/dist/plugins/ColumnTransformer.js +67 -0
  36. package/dist/plugins/EscapeHtmlBlockModifier.d.ts +2 -0
  37. package/dist/plugins/EscapeHtmlBlockModifier.js +41 -0
  38. package/dist/plugins/EscapeHtmlBlockModifier.spec.d.ts +1 -0
  39. package/dist/plugins/EscapeHtmlBlockModifier.spec.js +130 -0
  40. package/dist/plugins/HeadingTranformer.spec.d.ts +1 -0
  41. package/dist/plugins/HeadingTranformer.spec.js +46 -0
  42. package/dist/plugins/HeadingTransformer.d.ts +2 -0
  43. package/dist/plugins/HeadingTransformer.js +63 -0
  44. package/dist/plugins/NumberedListTransformer.d.ts +2 -0
  45. package/dist/plugins/NumberedListTransformer.js +55 -0
  46. package/dist/plugins/NumberedListTransformer.spec.d.ts +1 -0
  47. package/dist/plugins/NumberedListTransformer.spec.js +86 -0
  48. package/dist/plugins/TableTransformer.d.ts +5 -0
  49. package/dist/plugins/TableTransformer.js +70 -0
  50. package/dist/plugins/embedTweaks.d.ts +5 -0
  51. package/dist/plugins/embedTweaks.js +46 -0
  52. package/dist/plugins/embedTweaks.spec.d.ts +1 -0
  53. package/dist/plugins/embedTweaks.spec.js +230 -0
  54. package/dist/plugins/externalLinks.d.ts +2 -0
  55. package/dist/plugins/externalLinks.js +26 -0
  56. package/dist/plugins/externalLinks.spec.d.ts +1 -0
  57. package/dist/plugins/externalLinks.spec.js +132 -0
  58. package/dist/plugins/internalLinks.d.ts +6 -0
  59. package/dist/plugins/internalLinks.js +78 -0
  60. package/dist/plugins/internalLinks.spec.d.ts +1 -0
  61. package/dist/plugins/internalLinks.spec.js +442 -0
  62. package/dist/plugins/pluginTestRun.d.ts +10 -0
  63. package/dist/plugins/pluginTestRun.js +248 -0
  64. package/dist/plugins/pluginTypes.d.ts +42 -0
  65. package/dist/plugins/pluginTypes.js +2 -0
  66. package/dist/pull.d.ts +12 -0
  67. package/dist/pull.js +253 -0
  68. package/dist/run.d.ts +1 -0
  69. package/dist/run.js +35 -0
  70. package/dist/transform.d.ts +6 -0
  71. package/dist/transform.js +195 -0
  72. package/dist/types.d.ts +8 -0
  73. package/dist/types.js +2 -0
  74. package/package.json +96 -0
package/dist/images.js ADDED
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.cleanupOldImages = exports.parseImageBlock = exports.markdownToMDImageTransformer = exports.standardImageTransformer = exports.initImageHandling = void 0;
39
+ const fs = __importStar(require("fs-extra"));
40
+ const file_type_1 = __importDefault(require("file-type"));
41
+ const node_fetch_1 = __importDefault(require("node-fetch"));
42
+ const Path = __importStar(require("path"));
43
+ const MakeImagePersistencePlan_1 = require("./MakeImagePersistencePlan");
44
+ const log_1 = require("./log");
45
+ // We several things here:
46
+ // 1) copy images locally instead of leaving them in Notion
47
+ // 2) change the links to point here
48
+ // 3) read the caption and if there are localized images, get those too
49
+ // 4) prepare for localized documents, which need a copy of every image
50
+ let existingImagesNotSeenYetInPull = [];
51
+ let imageOutputPath = ""; // default to putting in the same directory as the document referring to it.
52
+ let imagePrefix = ""; // default to "./"
53
+ let locales;
54
+ function initImageHandling(prefix, outputPath, incomingLocales) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ // If they gave us a trailing slash, remove it because we add it back later.
57
+ // Note that it's up to the caller to have a *leading* slash or not.
58
+ imagePrefix = prefix.replace(/\/$/, "");
59
+ imageOutputPath = outputPath;
60
+ locales = incomingLocales;
61
+ // Currently we don't delete the image directory, because if an image
62
+ // changes, it gets a new id. This way can then prevent downloading
63
+ // and image after the 1st time. The downside is currently we don't
64
+ // have the smarts to remove unused images.
65
+ if (imageOutputPath) {
66
+ yield fs.mkdir(imageOutputPath, { recursive: true });
67
+ }
68
+ });
69
+ }
70
+ exports.initImageHandling = initImageHandling;
71
+ exports.standardImageTransformer = {
72
+ name: "DownloadImagesToRepo",
73
+ notionToMarkdownTransforms: [
74
+ {
75
+ type: "image",
76
+ // we have to set this one up for each page because we need to
77
+ // give it two extra parameters that are context for each page
78
+ getStringFromBlock: (context, block) => markdownToMDImageTransformer(block, context.directoryContainingMarkdown, context.relativeFilePathToFolderContainingPage),
79
+ },
80
+ ],
81
+ };
82
+ // This is a "custom transformer" function passed to notion-to-markdown
83
+ // eslint-disable-next-line @typescript-eslint/require-await
84
+ function markdownToMDImageTransformer(block, fullPathToDirectoryContainingMarkdown, relativePathToThisPage) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ const image = block.image;
87
+ yield processImageBlock(image, fullPathToDirectoryContainingMarkdown, relativePathToThisPage);
88
+ // just concatenate the caption text parts together
89
+ const altText = image.caption
90
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
91
+ .map((item) => item.plain_text)
92
+ .join("");
93
+ const href = image.type === "external" ? image.external.url : image.file.url;
94
+ return `![${altText}](${href})`;
95
+ });
96
+ }
97
+ exports.markdownToMDImageTransformer = markdownToMDImageTransformer;
98
+ function processImageBlock(imageBlock, pathToParentDocument, relativePathToThisPage) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ (0, log_1.logDebug)("processImageBlock", JSON.stringify(imageBlock));
101
+ const imageSet = parseImageBlock(imageBlock);
102
+ imageSet.pathToParentDocument = pathToParentDocument;
103
+ imageSet.relativePathToParentDocument = relativePathToThisPage;
104
+ // enhance: it would much better if we could split the changes to markdown separately from actual reading/writing,
105
+ // so that this wasn't part of the markdown-creation loop. It's already almost there; we just need to
106
+ // save the imageSets somewhere and then do the actual reading/writing later.
107
+ yield readPrimaryImage(imageSet);
108
+ (0, MakeImagePersistencePlan_1.makeImagePersistencePlan)(imageSet, imageOutputPath, imagePrefix);
109
+ yield saveImage(imageSet);
110
+ // change the src to point to our copy of the image
111
+ if ("file" in imageBlock) {
112
+ imageBlock.file.url = imageSet.filePathToUseInMarkdown;
113
+ }
114
+ else {
115
+ imageBlock.external.url = imageSet.filePathToUseInMarkdown;
116
+ }
117
+ // put back the simplified caption, stripped of the meta information
118
+ if (imageSet.caption) {
119
+ imageBlock.caption = [
120
+ {
121
+ type: "text",
122
+ text: { content: imageSet.caption, link: null },
123
+ plain_text: imageSet.caption,
124
+ },
125
+ ];
126
+ }
127
+ else {
128
+ imageBlock.caption = [];
129
+ }
130
+ });
131
+ }
132
+ function readPrimaryImage(imageSet) {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ const response = yield (0, node_fetch_1.default)(imageSet.primaryUrl);
135
+ const arrayBuffer = yield response.arrayBuffer();
136
+ imageSet.primaryBuffer = Buffer.from(arrayBuffer);
137
+ imageSet.fileType = yield file_type_1.default.fromBuffer(imageSet.primaryBuffer);
138
+ });
139
+ }
140
+ function saveImage(imageSet) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ writeImageIfNew(imageSet.primaryFileOutputPath, imageSet.primaryBuffer);
143
+ for (const localizedImage of imageSet.localizedUrls) {
144
+ let buffer = imageSet.primaryBuffer;
145
+ // if we have a urls for the localized screenshot, download it
146
+ if ((localizedImage === null || localizedImage === void 0 ? void 0 : localizedImage.url.length) > 0) {
147
+ (0, log_1.verbose)(`Retrieving ${localizedImage.iso632Code} version...`);
148
+ const response = yield (0, node_fetch_1.default)(localizedImage.url);
149
+ const arrayBuffer = yield response.arrayBuffer();
150
+ buffer = Buffer.from(arrayBuffer);
151
+ }
152
+ else {
153
+ (0, log_1.verbose)(`No localized image specified for ${localizedImage.iso632Code}, will use primary image.`);
154
+ // otherwise, we're going to fall back to outputting the primary image here
155
+ }
156
+ const directory = `./i18n/${localizedImage.iso632Code}/docusaurus-plugin-content-docs/current/${imageSet.relativePathToParentDocument}`;
157
+ writeImageIfNew((directory + "/" + imageSet.outputFileName).replaceAll("//", "/"), buffer);
158
+ }
159
+ });
160
+ }
161
+ function writeImageIfNew(path, buffer) {
162
+ imageWasSeen(path);
163
+ // Note: it's tempting to not spend time writing this out if we already have
164
+ // it from a previous run. But we don't really know it's the same. A) it
165
+ // could just have the same name, B) it could have been previously
166
+ // unlocalized and thus filled with a copy of the primary language image
167
+ // while and now is localized.
168
+ if (fs.pathExistsSync(path)) {
169
+ (0, log_1.verbose)("Replacing image " + path);
170
+ }
171
+ else {
172
+ (0, log_1.verbose)("Adding image " + path);
173
+ fs.mkdirsSync(Path.dirname(path));
174
+ }
175
+ fs.createWriteStream(path).write(buffer); // async but we're not waiting
176
+ }
177
+ function parseImageBlock(image) {
178
+ var _a;
179
+ if (!locales)
180
+ throw Error("Did you call initImageHandling()?");
181
+ const imageSet = {
182
+ primaryUrl: "",
183
+ caption: "",
184
+ localizedUrls: locales.map(l => ({ iso632Code: l, url: "" })),
185
+ };
186
+ if ("file" in image) {
187
+ imageSet.primaryUrl = image.file.url; // image saved on notion (actually AWS)
188
+ }
189
+ else {
190
+ imageSet.primaryUrl = image.external.url; // image still pointing somewhere else. I've see this happen when copying a Google Doc into Notion. Notion kep pointing at the google doc.
191
+ }
192
+ const mergedCaption = image.caption
193
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
194
+ .map((c) => c.plain_text)
195
+ .join("");
196
+ const lines = mergedCaption.split("\n");
197
+ // Example:
198
+ // Caption before images.\nfr https://i.imgur.com/pYmE7OJ.png\nES https://i.imgur.com/8paSZ0i.png\nCaption after images
199
+ lines.forEach(l => {
200
+ const match = /\s*(..)\s*(https:\/\/.*)/.exec(l);
201
+ if (match) {
202
+ imageSet.localizedUrls.push({
203
+ iso632Code: match[1].toLowerCase(),
204
+ url: match[2],
205
+ });
206
+ }
207
+ else {
208
+ // NB: carriage returns seem to mess up the markdown, so should be removed
209
+ imageSet.caption += l + " ";
210
+ }
211
+ });
212
+ // NB: currently notion-md puts the caption in Alt, which noone sees (unless the image isn't found)
213
+ // We could inject a custom element handler to emit a <figure> in order to show the caption.
214
+ imageSet.caption = (_a = imageSet.caption) === null || _a === void 0 ? void 0 : _a.trim();
215
+ //console.log(JSON.stringify(imageSet, null, 2));
216
+ return imageSet;
217
+ }
218
+ exports.parseImageBlock = parseImageBlock;
219
+ function imageWasSeen(path) {
220
+ existingImagesNotSeenYetInPull = existingImagesNotSeenYetInPull.filter(p => p !== path);
221
+ }
222
+ function cleanupOldImages() {
223
+ return __awaiter(this, void 0, void 0, function* () {
224
+ for (const p of existingImagesNotSeenYetInPull) {
225
+ (0, log_1.verbose)(`Removing old image: ${p}`);
226
+ yield fs.rm(p);
227
+ }
228
+ });
229
+ }
230
+ exports.cleanupOldImages = cleanupOldImages;
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ export * as Log from "./log";
3
+ export * from "./types";
4
+ export * from "./config/configuration";
5
+ export * from "./plugins/pluginTypes";
6
+ import type { IDocuNotionConfig } from "./config/configuration";
7
+ export type { IDocuNotionConfig };
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
26
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
27
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.Log = void 0;
31
+ const run_1 = require("./run");
32
+ (0, run_1.run)();
33
+ // for plugins to import
34
+ exports.Log = __importStar(require("./log"));
35
+ __exportStar(require("./types"), exports);
36
+ __exportStar(require("./config/configuration"), exports);
37
+ __exportStar(require("./plugins/pluginTypes"), exports);
package/dist/log.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ type levels = "info" | "verbose" | "debug";
2
+ export declare function setLogLevel(l: levels): void;
3
+ export declare function error(s: string): void;
4
+ export declare function warning(s: string): void;
5
+ export declare function info(s: string): void;
6
+ export declare function group(s: string): void;
7
+ export declare function endGroup(): void;
8
+ export declare function verbose(s: string): void;
9
+ export declare function logDebugFn(label: string, runIfLoggingDebug: () => string): void;
10
+ export declare function logDebug(label: string, info: string): void;
11
+ export {};
package/dist/log.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logDebug = exports.logDebugFn = exports.verbose = exports.endGroup = exports.group = exports.info = exports.warning = exports.error = exports.setLogLevel = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ chalk_1.default;
9
+ let logLevel;
10
+ function setLogLevel(l) {
11
+ logLevel = l;
12
+ }
13
+ exports.setLogLevel = setLogLevel;
14
+ function error(s) {
15
+ console.error(chalk_1.default.red(wrapForCI(s, "error")));
16
+ }
17
+ exports.error = error;
18
+ function warning(s) {
19
+ console.log(chalk_1.default.hex("#FFA500")(wrapForCI(s, "warning")));
20
+ }
21
+ exports.warning = warning;
22
+ function info(s) {
23
+ console.log(s);
24
+ }
25
+ exports.info = info;
26
+ // make sure to call endGroup(), eventually, after calling this
27
+ function group(s) {
28
+ console.log(chalk_1.default.blue(wrapForCI(s, "group")));
29
+ }
30
+ exports.group = group;
31
+ // github actions needs an ::endgroup:: to end a group
32
+ function endGroup() {
33
+ console.log(wrapForCI("", "endgroup"));
34
+ }
35
+ exports.endGroup = endGroup;
36
+ function verbose(s) {
37
+ if (logLevel === "verbose" || logLevel === "debug")
38
+ console.log(chalk_1.default.green(s));
39
+ }
40
+ exports.verbose = verbose;
41
+ // use this one if the debug info would take time to construct,
42
+ // so you want to skip doing it if not in debug mode
43
+ function logDebugFn(label, runIfLoggingDebug) {
44
+ if (logLevel === "debug") {
45
+ logDebug(label, runIfLoggingDebug());
46
+ }
47
+ }
48
+ exports.logDebugFn = logDebugFn;
49
+ function logDebug(label, info) {
50
+ if (logLevel === "debug") {
51
+ console.log(chalk_1.default.dim(wrapForCI(`[${label}]`, "debug")));
52
+ console.log(chalk_1.default.dim(wrapForCI(info, "debug")));
53
+ }
54
+ }
55
+ exports.logDebug = logDebug;
56
+ function wrapForCI(s, githubActionsPrefix) {
57
+ // for now, we only know about github actions, but submit a PR if you want to add more
58
+ return process.env["GITHUB_ACTIONS"] === "true"
59
+ ? `::${githubActionsPrefix}::${s}`
60
+ : s;
61
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const MakeImagePersistencePlan_1 = require("./MakeImagePersistencePlan");
4
+ test("primary file with explicit file output path and prefix", () => {
5
+ const imageSet = {
6
+ primaryUrl: "https://s3.us-west-2.amazonaws.com/primaryImage?Blah=foo",
7
+ localizedUrls: [],
8
+ pathToParentDocument: "/pathToParentSomewhere/",
9
+ fileType: { ext: "png", mime: "image/png" },
10
+ };
11
+ (0, MakeImagePersistencePlan_1.makeImagePersistencePlan)(imageSet, "./static/notion_imgs", "/notion_imgs");
12
+ expect(imageSet.outputFileName).toBe("463556435.png");
13
+ expect(imageSet.primaryFileOutputPath).toBe("static/notion_imgs/463556435.png");
14
+ expect(imageSet.filePathToUseInMarkdown).toBe("/notion_imgs/463556435.png");
15
+ });
16
+ test("primary file with defaults for image output path and prefix", () => {
17
+ const imageSet = {
18
+ primaryUrl: "https://s3.us-west-2.amazonaws.com/primaryImage?Blah=foo",
19
+ localizedUrls: [],
20
+ pathToParentDocument: "/pathToParentSomewhere/",
21
+ fileType: { ext: "png", mime: "image/png" },
22
+ };
23
+ (0, MakeImagePersistencePlan_1.makeImagePersistencePlan)(imageSet, "", "");
24
+ expect(imageSet.outputFileName).toBe("463556435.png");
25
+ // the default behavior is to put the image next to the markdown file
26
+ expect(imageSet.primaryFileOutputPath).toBe("/pathToParentSomewhere/463556435.png");
27
+ expect(imageSet.filePathToUseInMarkdown).toBe("./463556435.png");
28
+ });
29
+ // In order to make image fallback work with other languages, we have to have
30
+ // a file for each image, in each Docusaurus language directory. This is true
31
+ // whether we have a localized version of the image or not.
32
+ // The imageSet is initially populated with placeholders for each language.
33
+ // This test ensures that these placeholders are replaced with actual urls
34
+ // when localized versions of the image are listed.
35
+ // TODO write this test
@@ -0,0 +1,58 @@
1
+ /* Note, I haven't figure out how a Docusaurus app can actually include this, yet.
2
+ So currently this has to be duplicated by the client.
3
+ */
4
+
5
+ /* Copied from
6
+ https://github1s.com/NotionX/react-notion-x/blob/master/packages/react-notion-x/src/styles.css#L934
7
+ and
8
+ https://github1s.com/NotionX/react-notion-x/blob/master/packages/react-notion-x/src/styles.css#L1063
9
+ */
10
+ .notion-column {
11
+ display: flex;
12
+ flex-direction: column;
13
+ padding-top: 12px;
14
+ padding-bottom: 12px;
15
+ }
16
+
17
+ .notion-column > *:first-child {
18
+ margin-top: 0;
19
+ margin-left: 0;
20
+ margin-right: 0;
21
+ }
22
+
23
+ .notion-column > *:last-child {
24
+ margin-left: 0;
25
+ margin-right: 0;
26
+ margin-bottom: 0;
27
+ }
28
+
29
+ .notion-row {
30
+ display: flex;
31
+ overflow: hidden;
32
+ width: 100%;
33
+ max-width: 100%;
34
+ }
35
+
36
+ @media (max-width: 640px) {
37
+ .notion-row {
38
+ flex-direction: column;
39
+ }
40
+
41
+ .notion-row .notion-column {
42
+ width: 100% !important;
43
+ }
44
+
45
+ .notion-row .notion-spacer {
46
+ display: none;
47
+ }
48
+ }
49
+
50
+ .notion-spacer {
51
+ /* This matches the value in ColumnTransformer.ts */
52
+ width: calc(min(32px, 4vw));
53
+ }
54
+
55
+ .notion-spacer:last-child {
56
+ display: none;
57
+ }
58
+ /* End copied from NotionX */
@@ -0,0 +1,24 @@
1
+ import { IPlugin } from "./pluginTypes";
2
+ type TextRequest = string;
3
+ type Annotations = {
4
+ bold: boolean;
5
+ italic: boolean;
6
+ strikethrough: boolean;
7
+ underline: boolean;
8
+ code: boolean;
9
+ color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
10
+ };
11
+ export type Text = {
12
+ type: "text";
13
+ text: {
14
+ content: string;
15
+ link: {
16
+ url: TextRequest;
17
+ } | null;
18
+ };
19
+ annotations: Annotations;
20
+ plain_text: string;
21
+ href: string | null;
22
+ };
23
+ export declare const standardCalloutTransformer: IPlugin;
24
+ export {};
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.standardCalloutTransformer = void 0;
13
+ // In Notion, you can make a callout and change its emoji. We map 5 of these
14
+ // to the 5 Docusaurus admonition styles.
15
+ // This is mostly a copy of the callout code from notion-to-md. The change is to output docusaurus
16
+ // admonitions instead of emulating a callout with markdown > syntax.
17
+ // Note: I haven't yet tested this with any emoji except "💡"/"tip", nor the case where the
18
+ // callout has-children. Not even sure what that would mean, since the document I was testing
19
+ // with has quite complex markup inside the callout, but still takes the no-children branch.
20
+ function notionCalloutToAdmonition(notionToMarkdown, getBlockChildren, block) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ // In this case typescript is not able to index the types properly, hence ignoring the error
23
+ // @ts-ignore
24
+ const blockContent = block.callout.text || block.callout.rich_text || [];
25
+ // @ts-ignore
26
+ const icon = block.callout.icon;
27
+ let parsedData = "";
28
+ blockContent.map((content) => {
29
+ const annotations = content.annotations;
30
+ let plain_text = content.plain_text;
31
+ plain_text = notionToMarkdown.annotatePlainText(plain_text, annotations);
32
+ if (content["href"])
33
+ plain_text = `[${plain_text}](${content["href"]})`;
34
+ parsedData += plain_text;
35
+ });
36
+ let callout_string = "";
37
+ const { id, has_children } = block;
38
+ if (!has_children) {
39
+ const result1 = callout(parsedData, icon);
40
+ return result1;
41
+ }
42
+ const callout_children_object = yield getBlockChildren(id);
43
+ // // parse children blocks to md object
44
+ const callout_children = yield notionToMarkdown.blocksToMarkdown(callout_children_object);
45
+ callout_string += `${parsedData}\n`;
46
+ callout_children.map(child => {
47
+ callout_string += `${child.parent}\n\n`;
48
+ });
49
+ const result = callout(callout_string.trim(), icon);
50
+ return result;
51
+ });
52
+ }
53
+ const calloutsToAdmonitions = {
54
+ /* prettier-ignore */ "ℹ️": "note",
55
+ "📝": "note",
56
+ "💡": "tip",
57
+ "❗": "info",
58
+ "⚠️": "caution",
59
+ "🔥": "danger",
60
+ };
61
+ // This is the main change from the notion-to-md code.
62
+ function callout(text, icon) {
63
+ var _a;
64
+ let emoji;
65
+ if ((icon === null || icon === void 0 ? void 0 : icon.type) === "emoji") {
66
+ emoji = icon.emoji;
67
+ }
68
+ let docusaurusAdmonition = "note";
69
+ if (emoji) {
70
+ // the keyof typeof magic persuades typescript that it really is OK to use emoji as a key into calloutsToAdmonitions
71
+ docusaurusAdmonition =
72
+ (_a = calloutsToAdmonitions[emoji]) !== null && _a !== void 0 ? _a :
73
+ // For Notion callouts with other emojis, pass them through using hte emoji as the name.
74
+ // For this to work on a Docusaurus site, it will need to define that time on the remark-admonitions options in the docusaurus.config.js.
75
+ // See https://github.com/elviswolcott/remark-admonitions and https://docusaurus.io/docs/using-plugins#using-presets.
76
+ emoji;
77
+ }
78
+ return `:::${docusaurusAdmonition}\n\n${text}\n\n:::\n\n`;
79
+ }
80
+ exports.standardCalloutTransformer = {
81
+ name: "standardCalloutTransformer",
82
+ notionToMarkdownTransforms: [
83
+ {
84
+ type: "callout",
85
+ getStringFromBlock: (context, block) => notionCalloutToAdmonition(context.notionToMarkdown, context.getBlockChildren, block),
86
+ },
87
+ ],
88
+ };
@@ -0,0 +1 @@
1
+ export {};