Skip to content

Commit ecea439

Browse files
authored
update stuff
2 parents caab1b3 + fac61f1 commit ecea439

File tree

16 files changed

+7923
-10530
lines changed

16 files changed

+7923
-10530
lines changed

.eslintignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

.eslintrc

Lines changed: 1 addition & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,3 @@
11
{
2-
"extends": "airbnb-base",
3-
"parserOptions": {
4-
"sourceType": "script"
5-
},
6-
7-
"rules": {
8-
// Customized
9-
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
10-
"comma-dangle": ["error", {
11-
"arrays": "always-multiline",
12-
"objects": "always-multiline",
13-
"imports": "always-multiline",
14-
"exports": "always-multiline",
15-
"functions": "never"
16-
}],
17-
"no-empty": ["error", { "allowEmptyCatch": true }],
18-
"no-underscore-dangle": "off",
19-
"newline-per-chained-call": "off",
20-
"no-console": "off",
21-
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
22-
"strict": ["error", "global"],
23-
"consistent-return": "off",
24-
"func-names": "off",
25-
"no-tabs": "off",
26-
"indent": ["error", "tab"],
27-
"no-eq-null": "off",
28-
"camelcase": "off",
29-
"no-new": "off",
30-
"no-shadow": "off",
31-
"no-use-before-define": ["error", "nofunc"],
32-
"no-prototype-builtins": "off",
33-
"new-cap": "off",
34-
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
35-
"import/no-unresolved": "error",
36-
37-
// ES6
38-
"prefer-rest-params": "off",
39-
"prefer-spread": "off",
40-
"prefer-arrow-callback": "off",
41-
"prefer-template": "off",
42-
"no-var": "off",
43-
"object-shorthand": "off",
44-
"vars-on-top": "off",
45-
46-
// TODO
47-
"import/no-extraneous-dependencies": "off",
48-
"import/no-dynamic-require": "off",
49-
"import/newline-after-import": "off",
50-
"no-bitwise": "off",
51-
"global-require": "off",
52-
"max-len": "off",
53-
"no-param-reassign": "off",
54-
"no-restricted-syntax": "off",
55-
"no-script-url": "off",
56-
"default-case": "off",
57-
"linebreak-style": "off",
58-
59-
// "no-multi-assign": "off",
60-
// "one-var": "off",
61-
// "no-undef": "off",
62-
// "max-nested-callbacks": "off",
63-
// "no-mixed-requires": "off",
64-
// "brace-style": "off",
65-
// "max-statements-per-line": "off",
66-
// "no-unused-vars": "off",
67-
// "no-mixed-spaces-and-tabs": "off",
68-
// "no-useless-concat": "off",
69-
// "require-jsdoc": "off",
70-
// "eqeqeq": "off",
71-
// "no-negated-condition": "off",
72-
// "one-var-declaration-per-line": "off",
73-
// "no-lonely-if": "off",
74-
// "radix": "off",
75-
// "no-else-return": "off",
76-
// "no-useless-escape": "off",
77-
// "block-scoped-var": "off",
78-
// "operator-assignment": "off",
79-
// "yoda": "off",
80-
// "no-loop-func": "off",
81-
// "no-void": "off",
82-
// "valid-jsdoc": "off",
83-
// "no-cond-assign": "off",
84-
// "no-redeclare": "off",
85-
// "no-unreachable": "off",
86-
// "no-nested-ternary": "off",
87-
// "operator-linebreak": "off",
88-
// "guard-for-in": "off",
89-
// "no-unneeded-ternary": "off",
90-
// "no-sequences": "off",
91-
// "no-extend-native": "off",
92-
// "no-shadow-restricted-names": "off",
93-
// "no-extra-boolean-cast": "off",
94-
// "no-path-concat": "off",
95-
// "no-unused-expressions": "off",
96-
// "no-return-assign": "off",
97-
// "no-restricted-modules": "off",
98-
// "object-curly-spacing": "off",
99-
// "indent": "off",
100-
// "padded-blocks": "off",
101-
// "eol-last": "off",
102-
// "lines-around-directive": "off",
103-
// "strict": "off",
104-
// "comma-dangle": "off",
105-
// "no-multi-spaces": "off",
106-
// "quotes": "off",
107-
// "keyword-spacing": "off",
108-
// "no-mixed-operators": "off",
109-
// "comma-spacing": "off",
110-
// "no-trailing-spaces": "off",
111-
// "key-spacing": "off",
112-
// "no-multiple-empty-lines": "off",
113-
// "spaced-comment": "off",
114-
// "space-in-parens": "off",
115-
// "block-spacing": "off",
116-
// "quote-props": "off",
117-
// "space-unary-ops": "off",
118-
// "no-empty": "off",
119-
// "dot-notation": "off",
120-
// "func-call-spacing": "off",
121-
// "array-bracket-spacing": "off",
122-
// "object-property-newline": "off",
123-
// "no-continue": "off",
124-
// "no-extra-semi": "off",
125-
// "no-spaced-func": "off",
126-
// "no-useless-return": "off"
127-
}
2+
"extends": "nodebb"
1283
}

index.js

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ let parser;
2323
const Markdown = {
2424
config: {},
2525
_externalImageCache: undefined,
26+
_externalImageFailures: new Set(),
2627
onLoad: async function (params) {
2728
const controllers = require('./lib/controllers');
2829
const hostMiddleware = require.main.require('./src/middleware');
29-
const middlewares = [hostMiddleware.maintenanceMode, hostMiddleware.registrationComplete, hostMiddleware.pluginHooks];
30+
const middlewares = [
31+
hostMiddleware.maintenanceMode, hostMiddleware.registrationComplete, hostMiddleware.pluginHooks,
32+
];
3033

3134
params.router.get('/admin/plugins/markdown', params.middleware.admin.buildHeader, controllers.renderAdmin);
3235
params.router.get('/api/admin/plugins/markdown', controllers.renderAdmin);
@@ -35,35 +38,36 @@ const Markdown = {
3538
params.router.get('/api/post/:pid/raw', middlewares, controllers.retrieveRaw);
3639

3740
Markdown.init();
38-
Markdown.loadThemes();
41+
await Markdown.loadThemes();
3942

4043
return params;
4144
},
4245

43-
getConfig: function (config) {
46+
getConfig: async (config) => {
47+
const { defaultHighlightLanguage, highlightTheme } = await meta.settings.get('markdown');
48+
4449
config.markdown = {
4550
highlight: Markdown.highlight ? 1 : 0,
4651
highlightLinesLanguageList: Markdown.config.highlightLinesLanguageList,
47-
theme: Markdown.config.highlightTheme || 'railscasts.css',
52+
theme: highlightTheme || 'default.css',
53+
defaultHighlightLanguage: defaultHighlightLanguage || '',
4854
};
55+
4956
return config;
5057
},
5158

52-
getLinkTags: function (hookData) {
59+
getLinkTags: async (hookData) => {
60+
const { highlightTheme } = await meta.settings.get('markdown');
61+
5362
hookData.links.push({
5463
rel: 'prefetch stylesheet',
5564
type: '',
56-
href: `${nconf.get('relative_path')}/plugins/nodebb-plugin-markdown/styles/${Markdown.config.highlightTheme || 'railscasts.css'}`,
65+
href: `${nconf.get('relative_path')}/assets/plugins/nodebb-plugin-markdown/styles/${highlightTheme || 'default.css'}`,
66+
}, {
67+
rel: 'prefetch',
68+
href: `${nconf.get('relative_path')}/assets/language/${meta.config.defaultLang || 'en-GB'}/markdown.json?${meta.config['cache-buster']}`,
5769
});
5870

59-
const prefetch = ['/assets/src/modules/highlight.js', `/assets/language/${meta.config.defaultLang || 'en-GB'}/markdown.json`];
60-
hookData.links = hookData.links.concat(
61-
prefetch.map((path) => ({
62-
rel: 'prefetch',
63-
href: nconf.get('relative_path') + path + '?' + meta.config['cache-buster'],
64-
}))
65-
);
66-
6771
return hookData;
6872
},
6973

@@ -76,7 +80,7 @@ const Markdown = {
7680
langPrefix: 'language-',
7781
highlight: true,
7882
highlightLinesLanguageList: [],
79-
highlightTheme: 'railscasts.css',
83+
highlightTheme: 'default.css',
8084

8185
probe: true,
8286
probeCacheSize: 256,
@@ -93,12 +97,12 @@ const Markdown = {
9397
};
9498
const notCheckboxes = ['langPrefix', 'highlightTheme', 'highlightLinesLanguageList', 'probeCacheSize'];
9599

96-
meta.settings.get('markdown', function (err, options) {
100+
meta.settings.get('markdown', (err, options) => {
97101
if (err) {
98102
winston.warn(`[plugin/markdown] Unable to retrieve settings, assuming defaults: ${err.message}`);
99103
}
100104

101-
for (const field in defaults) {
105+
Object.keys(defaults).forEach((field) => {
102106
// If not set in config (nil)
103107
if (!options.hasOwnProperty(field)) {
104108
_self.config[field] = defaults[field];
@@ -107,7 +111,7 @@ const Markdown = {
107111
} else {
108112
_self.config[field] = options[field];
109113
}
110-
}
114+
});
111115

112116
_self.highlight = _self.config.highlight;
113117
delete _self.config.highlight;
@@ -133,28 +137,21 @@ const Markdown = {
133137
name: 'markdown.externalImageCache',
134138
max: parseInt(_self.config.probeCacheSize, 10) || 256,
135139
length: function () { return 1; },
136-
maxAge: 1000 * 60 * 60 * 24, // 1 day
140+
maxAge: 1000 * 60 * 60 * 24, // 1 day
137141
});
138142
}
139143
});
140144
},
141145

142-
loadThemes: function () {
143-
fs.readdir(path.join(require.resolve('highlight.js'), '../../styles'), function (err, files) {
144-
if (err) {
145-
winston.error('[plugin/markdown] Could not load Markdown themes: ' + err.message);
146-
Markdown.themes = [];
147-
return;
148-
}
146+
loadThemes: async () => {
147+
try {
148+
const files = await fs.promises.readdir(path.join(require.resolve('highlight.js'), '../../styles'));
149149
const isStylesheet = /\.css$/;
150-
Markdown.themes = files.filter(function (file) {
151-
return isStylesheet.test(file);
152-
}).map(function (file) {
153-
return {
154-
name: file,
155-
};
156-
});
157-
});
150+
Markdown.themes = files.filter(file => isStylesheet.test(file));
151+
} catch (err) {
152+
winston.error(`[plugin/markdown] Could not load Markdown themes: ${err.message}`);
153+
Markdown.themes = [];
154+
}
158155
},
159156
parsePost: async function (data) {
160157
const env = await Markdown.beforeParse(data);
@@ -208,29 +205,36 @@ const Markdown = {
208205
// eslint-disable-next-line no-cond-assign
209206
while ((current = matcher.exec(data.postData.content)) !== null) {
210207
const match = current[1];
211-
if (match && Markdown.isExternalLink(match)) { // for security only parse external images
208+
if (match && Markdown.isExternalLink(match)) { // for security only parse external images
212209
const parsedUrl = url.parse(match);
213210
const filename = path.basename(parsedUrl.pathname);
214211
const size = Markdown._externalImageCache.get(match);
212+
213+
// Short-circuit to ignore previous failures
214+
const hasFailed = Markdown._externalImageFailures.has(match);
215+
if (hasFailed) {
216+
return;
217+
}
218+
215219
if (size) {
216220
env.images.set(filename, size);
217221
} else {
218-
try {
219-
// eslint-disable-next-line no-await-in-loop
220-
const size = await probe(match);
221-
222+
// Size checked asynchronously, see: https://github.com/tomas/needle/issues/389
223+
probe(match, {
224+
follow_max: 2,
225+
}).then((size) => {
222226
let { width, height } = size;
223227

224228
// Swap width and height if orientation bit is set
225229
if (size.orientation >= 5 && size.orientation <= 8) {
226230
[width, height] = [height, width];
227231
}
228232

229-
env.images.set(filename, { width, height });
230233
Markdown._externalImageCache.set(match, { width, height });
231-
} catch (e) {
232-
// No handling required
233-
}
234+
}).catch(() => {
235+
// Likely an issue getting the external image size, ignore in the future
236+
Markdown._externalImageFailures.add(match);
237+
});
234238
}
235239
}
236240
}
@@ -248,13 +252,9 @@ const Markdown = {
248252
const execute = function (html) {
249253
// Replace all italicised mentions back to regular mentions
250254
if (italicMention.test(html)) {
251-
html = html.replace(italicMention, function (match, slug) {
252-
return '@_' + slug + '_';
253-
});
255+
html = html.replace(italicMention, (match, slug) => `@_${slug}_`);
254256
} else if (boldMention.test(html)) {
255-
html = html.replace(boldMention, function (match, slug) {
256-
return '@__' + slug + '__';
257-
});
257+
html = html.replace(boldMention, (match, slug) => `@__${slug}__`);
258258
}
259259

260260
return html;
@@ -342,12 +342,15 @@ const Markdown = {
342342

343343
// Update renderer to add some classes to all images
344344
const renderImage = parser.renderer.rules.image || function (tokens, idx, options, env, self) {
345+
// eslint-disable-next-line prefer-spread,prefer-rest-params
345346
return self.renderToken.apply(self, arguments);
346347
};
347348
const renderLink = parser.renderer.rules.link_open || function (tokens, idx, options, env, self) {
349+
// eslint-disable-next-line prefer-spread,prefer-rest-params
348350
return self.renderToken.apply(self, arguments);
349351
};
350352
const renderTable = parser.renderer.rules.table_open || function (tokens, idx, options, env, self) {
353+
// eslint-disable-next-line prefer-spread,prefer-rest-params
351354
return self.renderToken.apply(self, arguments);
352355
};
353356

@@ -359,7 +362,7 @@ const Markdown = {
359362
// Validate the url
360363
if (!Markdown.isUrlValid(attributes.get('src'))) { return ''; }
361364

362-
token.attrSet('class', (token.attrGet('class') || '') + ' img-responsive img-markdown');
365+
token.attrSet('class', `${token.attrGet('class') || ''} img-responsive img-markdown`);
363366

364367
// Append sizes to images
365368
if (parsedSrc.pathname) {
@@ -440,7 +443,7 @@ const Markdown = {
440443
* get updated.
441444
*/
442445
const allowedRoots = [nconf.get('upload_url'), '/uploads'];
443-
const allowed = (pathname) => allowedRoots.some((root) => pathname.toString().startsWith(root) || pathname.toString().startsWith(nconf.get('relative_path') + root));
446+
const allowed = pathname => allowedRoots.some(root => pathname.toString().startsWith(root) || pathname.toString().startsWith(nconf.get('relative_path') + root));
444447

445448
try {
446449
const urlObj = url.parse(src, false, true);
@@ -461,9 +464,12 @@ const Markdown = {
461464
}
462465

463466
if (
464-
urlObj.host === null // Relative paths are always internal links...
465-
|| (urlObj.host === baseUrlObj.host && urlObj.protocol === baseUrlObj.protocol // Otherwise need to check that protocol and host match
466-
&& (nconf.get('relative_path').length > 0 ? urlObj.pathname.indexOf(nconf.get('relative_path')) === 0 : true)) // Subfolder installs need this additional check
467+
urlObj.host === null || // Relative paths are always internal links...
468+
(
469+
urlObj.host === baseUrlObj.host &&
470+
urlObj.protocol === baseUrlObj.protocol && // Otherwise need to check that protocol and host match
471+
(nconf.get('relative_path').length > 0 ? urlObj.pathname.indexOf(nconf.get('relative_path')) === 0 : true) // Subfolder installs need this additional check
472+
)
467473
) {
468474
return false;
469475
}

lib/controllers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Controllers.retrieveRaw = function retrieveRaw(req, res, next) {
1717
return next();
1818
}
1919

20-
posts.getPostField(pid, 'content', function (err, content) {
20+
posts.getPostField(pid, 'content', (err, content) => {
2121
if (err) {
2222
return next(err);
2323
}

0 commit comments

Comments
 (0)