@sillsdev/docu-notion 0.11.1
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.
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/dist/FlatGuidLayoutStrategy.d.ts +6 -0
- package/dist/FlatGuidLayoutStrategy.js +25 -0
- package/dist/HierarchicalNamedLayoutStrategy.d.ts +7 -0
- package/dist/HierarchicalNamedLayoutStrategy.js +80 -0
- package/dist/LayoutStrategy.d.ts +12 -0
- package/dist/LayoutStrategy.js +83 -0
- package/dist/MakeImagePersistencePlan.d.ts +2 -0
- package/dist/MakeImagePersistencePlan.js +66 -0
- package/dist/NotionImage-CaptionReading.spec.d.ts +1 -0
- package/dist/NotionImage-CaptionReading.spec.js +233 -0
- package/dist/NotionPage.d.ts +45 -0
- package/dist/NotionPage.js +229 -0
- package/dist/NotionPage.spec.d.ts +1 -0
- package/dist/NotionPage.spec.js +143 -0
- package/dist/config/configuration.d.ts +5 -0
- package/dist/config/configuration.js +86 -0
- package/dist/config/default.docunotion.config.d.ts +3 -0
- package/dist/config/default.docunotion.config.js +37 -0
- package/dist/images.d.ts +24 -0
- package/dist/images.js +230 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +37 -0
- package/dist/log.d.ts +11 -0
- package/dist/log.js +61 -0
- package/dist/makeImagePersistencePlan.spec.d.ts +1 -0
- package/dist/makeImagePersistencePlan.spec.js +35 -0
- package/dist/notion-styles.css +58 -0
- package/dist/plugins/CalloutTransformer.d.ts +24 -0
- package/dist/plugins/CalloutTransformer.js +88 -0
- package/dist/plugins/CalloutTransformer.spec.d.ts +1 -0
- package/dist/plugins/CalloutTransformer.spec.js +199 -0
- package/dist/plugins/ColumnListTransformer.d.ts +2 -0
- package/dist/plugins/ColumnListTransformer.js +34 -0
- package/dist/plugins/ColumnTransformer.d.ts +2 -0
- package/dist/plugins/ColumnTransformer.js +67 -0
- package/dist/plugins/EscapeHtmlBlockModifier.d.ts +2 -0
- package/dist/plugins/EscapeHtmlBlockModifier.js +41 -0
- package/dist/plugins/EscapeHtmlBlockModifier.spec.d.ts +1 -0
- package/dist/plugins/EscapeHtmlBlockModifier.spec.js +130 -0
- package/dist/plugins/HeadingTranformer.spec.d.ts +1 -0
- package/dist/plugins/HeadingTranformer.spec.js +46 -0
- package/dist/plugins/HeadingTransformer.d.ts +2 -0
- package/dist/plugins/HeadingTransformer.js +63 -0
- package/dist/plugins/NumberedListTransformer.d.ts +2 -0
- package/dist/plugins/NumberedListTransformer.js +55 -0
- package/dist/plugins/NumberedListTransformer.spec.d.ts +1 -0
- package/dist/plugins/NumberedListTransformer.spec.js +86 -0
- package/dist/plugins/TableTransformer.d.ts +5 -0
- package/dist/plugins/TableTransformer.js +70 -0
- package/dist/plugins/embedTweaks.d.ts +5 -0
- package/dist/plugins/embedTweaks.js +46 -0
- package/dist/plugins/embedTweaks.spec.d.ts +1 -0
- package/dist/plugins/embedTweaks.spec.js +230 -0
- package/dist/plugins/externalLinks.d.ts +2 -0
- package/dist/plugins/externalLinks.js +26 -0
- package/dist/plugins/externalLinks.spec.d.ts +1 -0
- package/dist/plugins/externalLinks.spec.js +132 -0
- package/dist/plugins/internalLinks.d.ts +7 -0
- package/dist/plugins/internalLinks.js +102 -0
- package/dist/plugins/internalLinks.spec.d.ts +1 -0
- package/dist/plugins/internalLinks.spec.js +505 -0
- package/dist/plugins/mermaidLinkPlugin.spec.d.ts +1 -0
- package/dist/plugins/mermaidLinkPlugin.spec.js +77 -0
- package/dist/plugins/pluginTestRun.d.ts +10 -0
- package/dist/plugins/pluginTestRun.js +252 -0
- package/dist/plugins/pluginTypes.d.ts +44 -0
- package/dist/plugins/pluginTypes.js +2 -0
- package/dist/pull.d.ts +12 -0
- package/dist/pull.js +255 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +35 -0
- package/dist/transform.d.ts +6 -0
- package/dist/transform.js +200 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +2 -0
- package/package.json +103 -0
|
@@ -0,0 +1,86 @@
|
|
|
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.loadConfigAsync = void 0;
|
|
39
|
+
const Cosmic = __importStar(require("cosmiconfig"));
|
|
40
|
+
const default_docunotion_config_1 = __importDefault(require("./default.docunotion.config"));
|
|
41
|
+
const log_1 = require("../log");
|
|
42
|
+
const cosmiconfig_typescript_loader_1 = require("cosmiconfig-typescript-loader");
|
|
43
|
+
const process_1 = require("process");
|
|
44
|
+
// read the plugins from the config file
|
|
45
|
+
// and add them to the map
|
|
46
|
+
function loadConfigAsync() {
|
|
47
|
+
var _a, _b, _c, _d, _e;
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
let config = default_docunotion_config_1.default;
|
|
50
|
+
try {
|
|
51
|
+
const cosmic = Cosmic.cosmiconfig("docu-notion", {
|
|
52
|
+
loaders: {
|
|
53
|
+
".ts": (0, cosmiconfig_typescript_loader_1.TypeScriptLoader)(),
|
|
54
|
+
},
|
|
55
|
+
searchPlaces: [`docu-notion.config.ts`],
|
|
56
|
+
});
|
|
57
|
+
const found = yield cosmic.search();
|
|
58
|
+
if (found) {
|
|
59
|
+
(0, log_1.verbose)(`Loading config from ${found.filepath}`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
(0, log_1.verbose)(`Did not find configuration file, using defaults.`);
|
|
63
|
+
}
|
|
64
|
+
const pluginsWithInitializers = (_b = (_a = found === null || found === void 0 ? void 0 : found.config) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.filter((p) => p.init !== undefined);
|
|
65
|
+
const initializers = pluginsWithInitializers === null || pluginsWithInitializers === void 0 ? void 0 : pluginsWithInitializers.map((p) => () => p.init(p));
|
|
66
|
+
yield Promise.all(initializers || []);
|
|
67
|
+
(_d = (_c = found === null || found === void 0 ? void 0 : found.config) === null || _c === void 0 ? void 0 : _c.plugins) === null || _d === void 0 ? void 0 : _d.forEach((plugin) => __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
if (plugin.init !== undefined) {
|
|
69
|
+
(0, log_1.verbose)(`Initializing plugin ${plugin.name}...`);
|
|
70
|
+
yield plugin.init(plugin);
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
73
|
+
// for now, all we have is plugins
|
|
74
|
+
config = {
|
|
75
|
+
plugins: default_docunotion_config_1.default.plugins.concat(((_e = found === null || found === void 0 ? void 0 : found.config) === null || _e === void 0 ? void 0 : _e.plugins) || []),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
(0, log_1.error)(e.message);
|
|
80
|
+
(0, process_1.exit)(1);
|
|
81
|
+
}
|
|
82
|
+
(0, log_1.verbose)(`Active plugins: [${config.plugins.map(p => p.name).join(", ")}]`);
|
|
83
|
+
return config;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
exports.loadConfigAsync = loadConfigAsync;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const embedTweaks_1 = require("../plugins/embedTweaks");
|
|
4
|
+
const images_1 = require("../images");
|
|
5
|
+
const internalLinks_1 = require("../plugins/internalLinks");
|
|
6
|
+
const CalloutTransformer_1 = require("../plugins/CalloutTransformer");
|
|
7
|
+
const ColumnListTransformer_1 = require("../plugins/ColumnListTransformer");
|
|
8
|
+
const ColumnTransformer_1 = require("../plugins/ColumnTransformer");
|
|
9
|
+
const EscapeHtmlBlockModifier_1 = require("../plugins/EscapeHtmlBlockModifier");
|
|
10
|
+
const HeadingTransformer_1 = require("../plugins/HeadingTransformer");
|
|
11
|
+
const NumberedListTransformer_1 = require("../plugins/NumberedListTransformer");
|
|
12
|
+
const TableTransformer_1 = require("../plugins/TableTransformer");
|
|
13
|
+
const externalLinks_1 = require("../plugins/externalLinks");
|
|
14
|
+
const defaultConfig = {
|
|
15
|
+
plugins: [
|
|
16
|
+
// Notion "Block" JSON modifiers
|
|
17
|
+
EscapeHtmlBlockModifier_1.standardEscapeHtmlBlockModifier,
|
|
18
|
+
HeadingTransformer_1.standardHeadingTransformer,
|
|
19
|
+
// Notion to Markdown transformers. Most things get transformed correctly by the notion-to-markdown library,
|
|
20
|
+
// but some things need special handling.
|
|
21
|
+
ColumnTransformer_1.standardColumnTransformer,
|
|
22
|
+
ColumnListTransformer_1.standardColumnListTransformer,
|
|
23
|
+
images_1.standardImageTransformer,
|
|
24
|
+
CalloutTransformer_1.standardCalloutTransformer,
|
|
25
|
+
TableTransformer_1.standardTableTransformer,
|
|
26
|
+
NumberedListTransformer_1.standardNumberedListTransformer,
|
|
27
|
+
// Link modifiers, which are special because they can read metadata from all the pages in order to figure out the correct url
|
|
28
|
+
internalLinks_1.standardInternalLinkConversion,
|
|
29
|
+
externalLinks_1.standardExternalLinkConversion,
|
|
30
|
+
// Regexps plus javascript `import`s that operate on the Markdown output
|
|
31
|
+
embedTweaks_1.imgurGifEmbed,
|
|
32
|
+
embedTweaks_1.gifEmbed,
|
|
33
|
+
embedTweaks_1.youtubeEmbed,
|
|
34
|
+
embedTweaks_1.vimeoEmbed,
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
exports.default = defaultConfig;
|
package/dist/images.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { FileTypeResult } from "file-type";
|
|
3
|
+
import { ListBlockChildrenResponseResult } from "notion-to-md/build/types";
|
|
4
|
+
import { IPlugin } from "./plugins/pluginTypes";
|
|
5
|
+
export type ImageSet = {
|
|
6
|
+
primaryUrl: string;
|
|
7
|
+
caption?: string;
|
|
8
|
+
localizedUrls: Array<{
|
|
9
|
+
iso632Code: string;
|
|
10
|
+
url: string;
|
|
11
|
+
}>;
|
|
12
|
+
pathToParentDocument?: string;
|
|
13
|
+
relativePathToParentDocument?: string;
|
|
14
|
+
primaryBuffer?: Buffer;
|
|
15
|
+
fileType?: FileTypeResult;
|
|
16
|
+
primaryFileOutputPath?: string;
|
|
17
|
+
outputFileName?: string;
|
|
18
|
+
filePathToUseInMarkdown?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function initImageHandling(prefix: string, outputPath: string, incomingLocales: string[]): Promise<void>;
|
|
21
|
+
export declare const standardImageTransformer: IPlugin;
|
|
22
|
+
export declare function markdownToMDImageTransformer(block: ListBlockChildrenResponseResult, fullPathToDirectoryContainingMarkdown: string, relativePathToThisPage: string): Promise<string>;
|
|
23
|
+
export declare function parseImageBlock(image: any): ImageSet;
|
|
24
|
+
export declare function cleanupOldImages(): Promise<void>;
|
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 ``;
|
|
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;
|
package/dist/index.d.ts
ADDED
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 {};
|