Update npm dependencies

Problem: Our dependencies are falling behind and it'd be nice to have
them up-to-date. The only big update it that Common-Good upgraded to the
latest version of Prettier.

Solution: Update them!
This commit is contained in:
Christian Bundy 2020-03-23 15:54:28 -07:00
parent 8c71d93ab3
commit 32465e5983
12 changed files with 1029 additions and 844 deletions

View File

@ -2,15 +2,15 @@ module.exports = {
env: {
commonjs: true,
es6: true,
node: true
node: true,
},
extends: "eslint:recommended",
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly"
SharedArrayBuffer: "readonly",
},
parserOptions: {
ecmaVersion: 2018
ecmaVersion: 2018,
},
rules: {}
rules: {},
};

View File

@ -17,5 +17,5 @@ os:
# Don't build arbitrary branches, just pull requests + master + semver tags.
branches:
only:
- master
- "/^v\\d+\\.\\d+\\.\\d+$/"
- master
- "/^v\\d+\\.\\d+\\.\\d+$/"

1108
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,8 @@
},
"dependencies": {
"@fraction/base16-css": "^1.1.0",
"@fraction/flotilla": "^4.0.1",
"@fraction/flotilla": "^4.0.0",
"@koa/router": "^8.0.0",
"debug": "^4.1.1",
"env-paths": "^2.2.0",
"highlight.js": "^9.18.1",
@ -31,12 +32,11 @@
"koa": "^2.7.0",
"koa-body": "^4.1.0",
"koa-mount": "^4.0.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"lodash": "^4.17.11",
"markdown-it": "^8.4.2",
"open": "7.0.0",
"pretty-ms": "^5.0.0",
"open": "^7.0.3",
"pretty-ms": "^6.0.0",
"pull-paramap": "^1.2.2",
"pull-sort": "^1.0.2",
"pull-stream": "^3.6.12",
@ -44,19 +44,19 @@
"sharp": "^0.23.0",
"ssb-client": "^4.9.0",
"ssb-config": "^3.4.4",
"ssb-markdown": "^6.0.4",
"ssb-markdown": "^6.0.5",
"ssb-mentions": "^0.5.2",
"ssb-msgs": "^5.2.0",
"ssb-ref": "^2.13.9",
"ssb-tangle": "^1.0.1",
"ssb-thread-schema": "^1.1.1",
"yargs": "^15.3.0"
"yargs": "^15.3.1"
},
"devDependencies": {
"changelog-version": "^1.0.1",
"common-good": "^1.1.20",
"husky": "^3.0.5",
"mkdirp": "^0.5.1",
"common-good": "^2.0.2",
"husky": "^4.0.0",
"mkdirp": "^1.0.0",
"nodemon": "^2.0.2",
"stylelint-config-recommended": "^3.0.0"
},

View File

@ -14,33 +14,33 @@ module.exports = (presets, defaultConfigFile) =>
describe:
"Automatically open app in web browser. Use --no-open to disable.",
default: _.get(presets, "open", true),
type: "boolean"
type: "boolean",
})
.options("offline", {
describe:
"Don't try to connect to scuttlebutt peers or pubs. This can be changed on the 'settings' page while Oasis is running.",
default: _.get(presets, "offline", false),
type: "boolean"
type: "boolean",
})
.options("host", {
describe: "Hostname for web app to listen on",
default: _.get(presets, "host", "localhost"),
type: "string"
type: "string",
})
.options("port", {
describe: "Port for web app to listen on",
default: _.get(presets, "port", 3000),
type: "number"
type: "number",
})
.options("public", {
describe:
"Assume Oasis is being hosted publicly, disable HTTP POST and redact messages from people who haven't given consent for public web hosting.",
default: _.get(presets, "public", false),
type: "boolean"
type: "boolean",
})
.options("debug", {
describe: "Use verbose output for debugging",
default: _.get(presets, "debug", false),
type: "boolean"
type: "boolean",
})
.epilog(`The defaults can be configured in ${defaultConfigFile}.`).argv;

View File

@ -13,7 +13,7 @@ module.exports = ({ host, port, middleware }) => {
const app = new Koa();
module.exports = app;
app.on("error", err => {
app.on("error", (err) => {
// Output full error objects
err.message = err.stack;
console.error(err);
@ -32,7 +32,7 @@ module.exports = ({ host, port, middleware }) => {
"img-src 'self'",
"form-action 'self'",
"media-src 'self'",
"style-src 'self' 'unsafe-inline'"
"style-src 'self' 'unsafe-inline'",
].join("; ");
// Disallow scripts.
@ -69,6 +69,6 @@ module.exports = ({ host, port, middleware }) => {
}
});
middleware.forEach(m => app.use(m));
middleware.forEach((m) => app.use(m));
app.listen({ host, port });
};

View File

@ -66,12 +66,12 @@ these settings the default. See the readme for details.`);
const oasisCheckPath = "/.well-known/oasis";
process.on("uncaughtException", function(err) {
process.on("uncaughtException", function (err) {
// This isn't `err.code` because TypeScript doesn't like that.
if (err["code"] === "EADDRINUSE") {
nodeHttp.get(url + oasisCheckPath, res => {
nodeHttp.get(url + oasisCheckPath, (res) => {
let rawData = "";
res.on("data", chunk => {
res.on("data", (chunk) => {
rawData += chunk;
});
res.on("end", () => {
@ -123,7 +123,7 @@ const { nav, ul, li, a } = require("hyperaxe");
const open = require("open");
const pull = require("pull-stream");
const requireStyle = require("require-style");
const router = require("koa-router")();
const router = require("@koa/router")();
const ssbMentions = require("ssb-mentions");
const ssbRef = require("ssb-ref");
const isSvg = require("is-svg");
@ -138,7 +138,7 @@ const cooler = ssb({ offline: config.offline });
const { about, blob, friend, meta, post, vote } = require("./models")({
cooler,
isPublic: config.public
isPublic: config.public,
});
const {
@ -162,7 +162,7 @@ const {
setLanguage,
settingsView,
topicsView,
summaryView
summaryView,
} = require("./views");
let sharp;
@ -178,11 +178,11 @@ const defaultTheme = "atelier-sulphurPool-light".toLowerCase();
const readmePath = path.join(__dirname, "..", "README.md");
const packagePath = path.join(__dirname, "..", "package.json");
fs.promises.readFile(readmePath, "utf8").then(text => {
fs.promises.readFile(readmePath, "utf8").then((text) => {
config.readme = text;
});
fs.promises.readFile(packagePath, "utf8").then(text => {
fs.promises.readFile(packagePath, "utf8").then((text) => {
config.version = JSON.parse(text).version;
});
@ -207,21 +207,21 @@ router
ctx.assert(ssbRef.isFeedId(message), 400, "Invalid feed link");
return next();
})
.get("/", async ctx => {
.get("/", async (ctx) => {
ctx.redirect("/mentions");
})
.get("/robots.txt", ctx => {
.get("/robots.txt", (ctx) => {
ctx.body = "User-agent: *\nDisallow: /";
})
.get(oasisCheckPath, ctx => {
.get(oasisCheckPath, (ctx) => {
ctx.body = "oasis";
})
.get("/public/popular/:period", async ctx => {
.get("/public/popular/:period", async (ctx) => {
const { period } = ctx.params;
const publicPopular = async ({ period }) => {
const messages = await post.popular({ period });
const option = somePeriod => {
const option = (somePeriod) => {
const lowerPeriod = somePeriod.toLowerCase();
return li(
period === lowerPeriod
@ -236,30 +236,30 @@ router
return popularView({
messages,
prefix
prefix,
});
};
ctx.body = await publicPopular({ period });
})
.get("/public/latest", async ctx => {
.get("/public/latest", async (ctx) => {
const messages = await post.latest();
ctx.body = await latestView({ messages });
})
.get("/public/latest/extended", async ctx => {
.get("/public/latest/extended", async (ctx) => {
const messages = await post.latestExtended();
ctx.body = await extendedView({ messages });
})
.get("/public/latest/topics", async ctx => {
.get("/public/latest/topics", async (ctx) => {
const messages = await post.latestTopics();
ctx.body = await topicsView({ messages });
})
.get("/public/latest/summaries", async ctx => {
.get("/public/latest/summaries", async (ctx) => {
const messages = await post.latestSummaries();
ctx.body = await summaryView({ messages });
})
.get("/author/:feed", async ctx => {
.get("/author/:feed", async (ctx) => {
const { feed } = ctx.params;
const author = async feedId => {
const author = async (feedId) => {
const description = await about.description(feedId);
const name = await about.name(feedId);
const image = await about.image(feedId);
@ -274,12 +274,12 @@ router
name,
description,
avatarUrl,
relationship
relationship,
});
};
ctx.body = await author(feed);
})
.get("/search/", async ctx => {
.get("/search/", async (ctx) => {
let { query } = ctx.query;
if (isMsg(query)) {
@ -305,7 +305,7 @@ router
ctx.body = await searchView({ messages, query });
})
.get("/inbox", async ctx => {
.get("/inbox", async (ctx) => {
const inbox = async () => {
const messages = await post.inbox();
@ -313,13 +313,13 @@ router
};
ctx.body = await inbox();
})
.get("/hashtag/:hashtag", async ctx => {
.get("/hashtag/:hashtag", async (ctx) => {
const { hashtag } = ctx.params;
const messages = await post.fromHashtag(hashtag);
ctx.body = await hashtagView({ hashtag, messages });
})
.get("/theme.css", ctx => {
.get("/theme.css", (ctx) => {
const theme = ctx.cookies.get("theme") || defaultTheme;
const packageName = "@fraction/base16-css";
@ -327,7 +327,7 @@ router
ctx.type = "text/css";
ctx.body = requireStyle(filePath);
})
.get("/profile/", async ctx => {
.get("/profile/", async (ctx) => {
const myFeedId = await meta.myFeedId();
const description = await about.description(myFeedId);
@ -344,20 +344,20 @@ router
name,
description,
avatarUrl,
relationship: null
relationship: null,
});
})
.get("/profile/edit", async ctx => {
.get("/profile/edit", async (ctx) => {
const myFeedId = await meta.myFeedId();
const description = await about.description(myFeedId);
const name = await about.name(myFeedId);
ctx.body = await editProfileView({
name,
description
description,
});
})
.post("/profile/edit", koaBody({ multipart: true }), async ctx => {
.post("/profile/edit", koaBody({ multipart: true }), async (ctx) => {
const name = String(ctx.request.body.name);
const description = String(ctx.request.body.description);
@ -365,14 +365,14 @@ router
ctx.body = await post.publishProfileEdit({
name,
description,
image
image,
});
ctx.redirect("/profile");
})
.get("/publish/custom/", async ctx => {
.get("/publish/custom/", async (ctx) => {
ctx.body = await publishCustomView();
})
.get("/json/:message", async ctx => {
.get("/json/:message", async (ctx) => {
if (config.public) {
throw new Error(
"Sorry, many actions are unavailable when Oasis is running in public mode. Please run Oasis in the default mode and try again."
@ -380,19 +380,19 @@ router
}
const { message } = ctx.params;
ctx.type = "application/json";
const json = async message => {
const json = async (message) => {
const json = await meta.get(message);
return JSON.stringify(json, null, 2);
};
ctx.body = await json(message);
})
.get("/blob/:blobId", async ctx => {
.get("/blob/:blobId", async (ctx) => {
const { blobId } = ctx.params;
const getBlob = async ({ blobId }) => {
const bufferSource = await blob.get({ blobId });
debug("got buffer source");
return new Promise(resolve => {
return new Promise((resolve) => {
pull(
bufferSource,
pull.collect(async (err, bufferArray) => {
@ -428,7 +428,7 @@ router
ctx.type = "image/svg+xml";
}
})
.get("/image/:imageSize/:blobId", async ctx => {
.get("/image/:imageSize/:blobId", async (ctx) => {
const { blobId, imageSize } = ctx.params;
if (sharp) {
ctx.type = "image/png";
@ -439,7 +439,7 @@ router
"base64"
);
const fakeImage = imageSize =>
const fakeImage = (imageSize) =>
sharp
? sharp({
create: {
@ -450,23 +450,23 @@ router
r: 0,
g: 0,
b: 0,
alpha: 0.5
}
}
alpha: 0.5,
},
},
})
.png()
.toBuffer()
: new Promise(resolve => resolve(fakePixel));
: new Promise((resolve) => resolve(fakePixel));
const image = async ({ blobId, imageSize }) => {
const bufferSource = await blob.get({ blobId });
const fakeId = "&0000000000000000000000000000000000000000000=.sha256";
debug("got buffer source");
return new Promise(resolve => {
return new Promise((resolve) => {
if (blobId === fakeId) {
debug("fake image");
fakeImage(imageSize).then(result => resolve(result));
fakeImage(imageSize).then((result) => resolve(result));
} else {
debug("not fake image");
pull(
@ -485,7 +485,7 @@ router
.resize(imageSize, imageSize)
.png()
.toBuffer()
.then(data => {
.then((data) => {
resolve(data);
});
} else {
@ -499,7 +499,7 @@ router
};
ctx.body = await image({ blobId, imageSize: Number(imageSize) });
})
.get("/settings/", async ctx => {
.get("/settings/", async (ctx) => {
const theme = ctx.cookies.get("theme") || defaultTheme;
const getMeta = async ({ theme }) => {
const status = await meta.status();
@ -516,12 +516,12 @@ router
peers: peersWithNames,
theme,
themeNames,
version: config.version
version: config.version,
});
};
ctx.body = await getMeta({ theme });
})
.get("/likes/:feed", async ctx => {
.get("/likes/:feed", async (ctx) => {
const { feed } = ctx.params;
const likes = async ({ feed }) => {
const pendingMessages = post.likes({ feed });
@ -529,18 +529,18 @@ router
return likesView({
messages: await pendingMessages,
feed,
name: await pendingName
name: await pendingName,
});
};
ctx.body = await likes({ feed });
})
.get("/settings/readme/", async ctx => {
const status = async text => {
.get("/settings/readme/", async (ctx) => {
const status = async (text) => {
return markdownView({ text });
};
ctx.body = await status(config.readme);
})
.get("/mentions/", async ctx => {
.get("/mentions/", async (ctx) => {
const mentions = async () => {
const messages = await post.mentionsMe();
@ -548,9 +548,9 @@ router
};
ctx.body = await mentions();
})
.get("/thread/:message", async ctx => {
.get("/thread/:message", async (ctx) => {
const { message } = ctx.params;
const thread = async message => {
const thread = async (message) => {
const messages = await post.fromThread(message);
debug("got %i messages", messages.length);
@ -559,9 +559,9 @@ router
ctx.body = await thread(message);
})
.get("/reply/:message", async ctx => {
.get("/reply/:message", async (ctx) => {
const { message } = ctx.params;
const reply = async parentId => {
const reply = async (parentId) => {
const rootMessage = await post.get(parentId);
const myFeedId = await meta.myFeedId();
@ -572,12 +572,12 @@ router
};
ctx.body = await reply(message);
})
.get("/publish", async ctx => {
.get("/publish", async (ctx) => {
ctx.body = await publishView();
})
.get("/comment/:message", async ctx => {
.get("/comment/:message", async (ctx) => {
const { message } = ctx.params;
const comment = async parentId => {
const comment = async (parentId) => {
const parentMessage = await post.get(parentId);
const myFeedId = await meta.myFeedId();
@ -602,7 +602,7 @@ router
};
ctx.body = await comment(message);
})
.post("/reply/:message", koaBody(), async ctx => {
.post("/reply/:message", koaBody(), async (ctx) => {
const { message } = ctx.params;
const text = String(ctx.request.body.text);
const publishReply = async ({ message, text }) => {
@ -612,13 +612,13 @@ router
const parent = await post.get(message);
return post.reply({
parent,
message: { text, mentions }
message: { text, mentions },
});
};
ctx.body = await publishReply({ message, text });
ctx.redirect(`/thread/${encodeURIComponent(message)}`);
})
.post("/comment/:message", koaBody(), async ctx => {
.post("/comment/:message", koaBody(), async (ctx) => {
const { message } = ctx.params;
const text = String(ctx.request.body.text);
const publishComment = async ({ message, text }) => {
@ -628,13 +628,13 @@ router
return post.comment({
parent,
message: { text, mentions }
message: { text, mentions },
});
};
ctx.body = await publishComment({ message, text });
ctx.redirect(`/thread/${encodeURIComponent(message)}`);
})
.post("/publish/", koaBody(), async ctx => {
.post("/publish/", koaBody(), async (ctx) => {
const text = String(ctx.request.body.text);
const rawContentWarning = String(ctx.request.body.contentWarning);
@ -648,31 +648,31 @@ router
return post.root({
text,
mentions,
contentWarning
contentWarning,
});
};
ctx.body = await publish({ text, contentWarning });
ctx.redirect("/public/latest");
})
.post("/publish/custom", koaBody(), async ctx => {
.post("/publish/custom", koaBody(), async (ctx) => {
const text = String(ctx.request.body.text);
const obj = JSON.parse(text);
ctx.body = await post.publishCustom(obj);
ctx.redirect(`/public/latest`);
})
.post("/follow/:feed", koaBody(), async ctx => {
.post("/follow/:feed", koaBody(), async (ctx) => {
const { feed } = ctx.params;
const referer = new URL(ctx.request.header.referer);
ctx.body = await friend.follow(feed);
ctx.redirect(referer);
})
.post("/unfollow/:feed", koaBody(), async ctx => {
.post("/unfollow/:feed", koaBody(), async (ctx) => {
const { feed } = ctx.params;
const referer = new URL(ctx.request.header.referer);
ctx.body = await friend.unfollow(feed);
ctx.redirect(referer);
})
.post("/like/:message", koaBody(), async ctx => {
.post("/like/:message", koaBody(), async (ctx) => {
const { message } = ctx.params;
// TODO: convert all so `message` is full message and `messageKey` is key
const messageKey = message;
@ -680,7 +680,7 @@ router
const voteValue = Number(ctx.request.body.voteValue);
const encoded = {
message: encodeURIComponent(message)
message: encodeURIComponent(message),
};
const referer = new URL(ctx.request.header.referer);
@ -693,7 +693,7 @@ router
const isPrivate = message.value.meta.private === true;
const messageRecipients = isPrivate ? message.value.content.recps : [];
const normalized = messageRecipients.map(recipient => {
const normalized = messageRecipients.map((recipient) => {
if (typeof recipient === "string") {
return recipient;
}
@ -712,31 +712,31 @@ router
ctx.body = await like({ messageKey, voteValue });
ctx.redirect(referer);
})
.post("/theme.css", koaBody(), async ctx => {
.post("/theme.css", koaBody(), async (ctx) => {
const theme = String(ctx.request.body.theme);
ctx.cookies.set("theme", theme);
const referer = new URL(ctx.request.header.referer);
ctx.redirect(referer);
})
.post("/language", koaBody(), async ctx => {
.post("/language", koaBody(), async (ctx) => {
const language = String(ctx.request.body.language);
ctx.cookies.set("language", language);
const referer = new URL(ctx.request.header.referer);
ctx.redirect(referer);
})
.post("/settings/conn/start", koaBody(), async ctx => {
.post("/settings/conn/start", koaBody(), async (ctx) => {
await meta.connStart();
ctx.redirect("/settings");
})
.post("/settings/conn/stop", koaBody(), async ctx => {
.post("/settings/conn/stop", koaBody(), async (ctx) => {
await meta.connStop();
ctx.redirect("/settings");
})
.post("/settings/conn/restart", koaBody(), async ctx => {
.post("/settings/conn/restart", koaBody(), async (ctx) => {
await meta.connRestart();
ctx.redirect("/settings");
})
.post("/settings/invite/accept", koaBody(), async ctx => {
.post("/settings/invite/accept", koaBody(), async (ctx) => {
const invite = String(ctx.request.body.invite);
await meta.acceptInvite(invite);
ctx.redirect("/settings");
@ -781,7 +781,7 @@ const middleware = [
await next();
}
},
routes
routes,
];
http({ host, port, middleware });

View File

@ -18,11 +18,11 @@ const nullImage = `&${"0".repeat(43)}=.sha256`;
const defaultOptions = {
private: true,
reverse: true,
meta: true
meta: true,
};
const publicOnlyFilter = pull.filter(
message => lodash.get(message, "value.meta.private", false) === false
(message) => lodash.get(message, "value.meta.private", false) === false
);
/** @param {object[]} customOptions */
@ -55,16 +55,19 @@ module.exports = ({ cooler, isPublic }) => {
{
$filter: {
dest: feedId,
value: { author: feedId, content: { type: "about", about: feedId } }
}
}
]
value: {
author: feedId,
content: { type: "about", about: feedId },
},
},
},
],
});
return new Promise((resolve, reject) =>
pull(
source,
pull.find(
message => message.value.content[key] !== undefined,
(message) => message.value.content[key] !== undefined,
(err, message) => {
if (err) {
reject(err);
@ -82,14 +85,14 @@ module.exports = ({ cooler, isPublic }) => {
};
models.about = {
publicWebHosting: async feedId => {
publicWebHosting: async (feedId) => {
const result = await getAbout({
key: "publicWebHosting",
feedId
feedId,
});
return result === true;
},
name: async feedId => {
name: async (feedId) => {
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
return "Redacted";
}
@ -97,18 +100,18 @@ module.exports = ({ cooler, isPublic }) => {
return (
(await getAbout({
key: "name",
feedId
feedId,
})) || feedId.slice(1, 1 + 8)
); // First 8 chars of public key
},
image: async feedId => {
image: async (feedId) => {
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
return nullImage;
}
const raw = await getAbout({
key: "image",
feedId
feedId,
});
if (raw == null || raw.link == null) {
@ -120,7 +123,7 @@ module.exports = ({ cooler, isPublic }) => {
}
return raw;
},
description: async feedId => {
description: async (feedId) => {
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
return "Redacted";
}
@ -128,10 +131,10 @@ module.exports = ({ cooler, isPublic }) => {
const raw =
(await getAbout({
key: "description",
feedId
feedId,
})) || "";
return raw;
}
},
};
models.blob = {
@ -146,17 +149,17 @@ module.exports = ({ cooler, isPublic }) => {
// This does not wait for the blob.
ssb.blobs.want(blobId);
}
},
};
models.friend = {
isFollowing: async feedId => {
isFollowing: async (feedId) => {
const ssb = await cooler.open();
const { id } = ssb;
const isFollowing = await ssb.friends.isFollowing({
source: id,
dest: feedId
dest: feedId,
});
return isFollowing;
},
@ -166,24 +169,24 @@ module.exports = ({ cooler, isPublic }) => {
const content = {
type: "contact",
contact: feedId,
following
following,
};
return ssb.publish(content);
},
follow: async feedId => {
follow: async (feedId) => {
const isFollowing = await models.friend.isFollowing(feedId);
if (!isFollowing) {
await models.friend.setFollowing({ feedId, following: true });
}
},
unfollow: async feedId => {
unfollow: async (feedId) => {
const isFollowing = await models.friend.isFollowing(feedId);
if (isFollowing) {
await models.friend.setFollowing({ feedId, following: false });
}
},
getRelationship: async feedId => {
getRelationship: async (feedId) => {
const ssb = await cooler.open();
const { id } = ssb;
@ -193,19 +196,19 @@ module.exports = ({ cooler, isPublic }) => {
const isFollowing = await ssb.friends.isFollowing({
source: id,
dest: feedId
dest: feedId,
});
const isBlocking = await ssb.friends.isBlocking({
source: id,
dest: feedId
dest: feedId,
});
return {
following: isFollowing,
blocking: isBlocking
blocking: isBlocking,
};
}
},
};
models.meta = {
@ -214,12 +217,12 @@ module.exports = ({ cooler, isPublic }) => {
const { id } = ssb;
return id;
},
get: async msgId => {
get: async (msgId) => {
const ssb = await cooler.open();
return ssb.get({
id: msgId,
meta: true,
private: true
private: true,
});
},
status: async () => {
@ -269,44 +272,44 @@ module.exports = ({ cooler, isPublic }) => {
await models.meta.connStop();
await models.meta.connStart();
},
acceptInvite: async invite => {
acceptInvite: async (invite) => {
const ssb = await cooler.open();
return await ssb.invite.accept(invite);
}
},
};
const isPost = message =>
const isPost = (message) =>
lodash.get(message, "value.content.type") === "post" &&
lodash.get(message, "value.content.text") != null;
const isLooseRoot = message => {
const isLooseRoot = (message) => {
const conditions = [
isPost(message),
lodash.get(message, "value.content.root") == null,
lodash.get(message, "value.content.fork") == null
lodash.get(message, "value.content.fork") == null,
];
return conditions.every(x => x);
return conditions.every((x) => x);
};
const isLooseReply = message => {
const isLooseReply = (message) => {
const conditions = [
isPost(message),
lodash.get(message, "value.content.root") != null,
lodash.get(message, "value.content.fork") != null
lodash.get(message, "value.content.fork") != null,
];
return conditions.every(x => x);
return conditions.every((x) => x);
};
const isLooseComment = message => {
const isLooseComment = (message) => {
const conditions = [
isPost(message),
lodash.get(message, "value.content.root") != null,
lodash.get(message, "value.content.fork") == null
lodash.get(message, "value.content.fork") == null,
];
return conditions.every(x => x === true);
return conditions.every((x) => x === true);
};
const maxMessages = 64;
@ -316,7 +319,7 @@ module.exports = ({ cooler, isPublic }) => {
customOptions,
ssb,
query,
filter = null
filter = null,
}) => {
const options = configure({ query, index: "DTA" }, customOptions);
@ -328,7 +331,7 @@ module.exports = ({ cooler, isPublic }) => {
source,
basicSocialFilter,
pull.filter(
msg =>
(msg) =>
typeof msg.value.content !== "string" &&
msg.value.content.type === "post" &&
(filter == null || filter(msg) === true)
@ -356,12 +359,12 @@ module.exports = ({ cooler, isPublic }) => {
const socialFilter = async ({
following = null,
blocking = false,
me = null
me = null,
} = {}) => {
const ssb = await cooler.open();
const { id } = ssb;
const relationshipObject = await ssb.friends.get({
source: id
source: id,
});
const followingList = Object.entries(relationshipObject)
@ -372,7 +375,7 @@ module.exports = ({ cooler, isPublic }) => {
.filter(([, val]) => val === false)
.map(([key]) => key);
return pull.filter(message => {
return pull.filter((message) => {
if (message.value.author === id) {
return me !== false;
} else {
@ -387,7 +390,7 @@ module.exports = ({ cooler, isPublic }) => {
};
const transform = (ssb, messages, myFeedId) =>
Promise.all(
messages.map(async msg => {
messages.map(async (msg) => {
debug("transforming %s", msg.key);
if (msg == null) {
@ -396,22 +399,22 @@ module.exports = ({ cooler, isPublic }) => {
const filterQuery = {
$filter: {
dest: msg.key
}
dest: msg.key,
},
};
const referenceStream = ssb.backlinks.read({
query: [filterQuery],
index: "DTA", // use asserted timestamps
private: true,
meta: true
meta: true,
});
const rawVotes = await new Promise((resolve, reject) => {
pull(
referenceStream,
pull.filter(
ref =>
(ref) =>
typeof ref.value.content !== "string" &&
ref.value.content.type === "vote" &&
ref.value.content.vote &&
@ -500,7 +503,7 @@ module.exports = ({ cooler, isPublic }) => {
lodash.set(msg, "value.meta.author.name", name);
lodash.set(msg, "value.meta.author.avatar", {
id: avatarId,
url: avatarUrl
url: avatarUrl,
});
const isPost =
@ -539,7 +542,7 @@ module.exports = ({ cooler, isPublic }) => {
pull(
source,
pull.filter(
msg =>
(msg) =>
lodash.get(msg, "value.meta.private", false) === false &&
msg.value.content.type === "post"
),
@ -564,9 +567,9 @@ module.exports = ({ cooler, isPublic }) => {
const query = [
{
$filter: {
dest: myFeedId
}
}
dest: myFeedId,
},
},
];
const messages = await getMessages({
@ -574,9 +577,9 @@ module.exports = ({ cooler, isPublic }) => {
customOptions,
ssb,
query,
filter: msg =>
filter: (msg) =>
msg.value.author !== myFeedId &&
lodash.get(msg, "value.meta.private") !== true
lodash.get(msg, "value.meta.private") !== true,
});
return messages;
@ -589,16 +592,16 @@ module.exports = ({ cooler, isPublic }) => {
const query = [
{
$filter: {
dest: `#${hashtag}`
}
}
dest: `#${hashtag}`,
},
},
];
const messages = await getMessages({
myFeedId,
customOptions,
ssb,
query
query,
});
return messages;
@ -611,9 +614,9 @@ module.exports = ({ cooler, isPublic }) => {
const query = [
{
$filter: {
dest: rootId
}
}
dest: rootId,
},
},
];
const messages = await getMessages({
@ -621,8 +624,8 @@ module.exports = ({ cooler, isPublic }) => {
customOptions,
ssb,
query,
filter: msg =>
msg.value.content.root === rootId && msg.value.content.fork == null
filter: (msg) =>
msg.value.content.root === rootId && msg.value.content.fork == null,
});
return messages;
@ -637,17 +640,17 @@ module.exports = ({ cooler, isPublic }) => {
author: feed,
timestamp: { $lte: Date.now() },
content: {
type: "vote"
}
}
}
}
type: "vote",
},
},
},
},
];
const options = configure(
{
query,
reverse: true
reverse: true,
},
customOptions
);
@ -657,7 +660,7 @@ module.exports = ({ cooler, isPublic }) => {
const messages = await new Promise((resolve, reject) => {
pull(
source,
pull.filter(msg => {
pull.filter((msg) => {
return (
typeof msg.value.content === "object" &&
msg.value.author === feed &&
@ -688,7 +691,7 @@ module.exports = ({ cooler, isPublic }) => {
const myFeedId = ssb.id;
const options = configure({
query
query,
});
const source = await ssb.search.query(options);
@ -729,12 +732,12 @@ module.exports = ({ cooler, isPublic }) => {
value: {
timestamp: { $lte: Date.now() },
content: {
type: "post"
}
}
}
}
]
type: "post",
},
},
},
},
],
})
);
const followingFilter = await socialFilter({ following: true });
@ -770,18 +773,18 @@ module.exports = ({ cooler, isPublic }) => {
value: {
timestamp: { $lte: Date.now() },
content: {
type: "post"
}
}
}
}
]
type: "post",
},
},
},
},
],
})
);
const extendedFilter = await socialFilter({
following: false,
me: false
me: false,
});
const messages = await new Promise((resolve, reject) => {
@ -815,24 +818,24 @@ module.exports = ({ cooler, isPublic }) => {
value: {
timestamp: { $lte: Date.now() },
content: {
type: "post"
}
}
}
}
]
type: "post",
},
},
},
},
],
})
);
const extendedFilter = await socialFilter({
following: true
following: true,
});
const messages = await new Promise((resolve, reject) => {
pull(
source,
publicOnlyFilter,
pull.filter(message => message.value.content.root == null),
pull.filter((message) => message.value.content.root == null),
extendedFilter,
pull.take(maxMessages),
pull.collect((err, collectedMessages) => {
@ -854,20 +857,20 @@ module.exports = ({ cooler, isPublic }) => {
const options = configure({
type: "post",
private: false
private: false,
});
const source = ssb.messagesByType(options);
const extendedFilter = await socialFilter({
following: true
following: true,
});
const messages = await new Promise((resolve, reject) => {
pull(
source,
pull.filter(
message =>
(message) =>
typeof message.value.content !== "string" &&
message.value.content.root == null
),
@ -903,7 +906,7 @@ module.exports = ({ cooler, isPublic }) => {
day: 1,
week: 7,
month: 30.42,
year: 365
year: 365,
};
if (period in periodDict === false) {
@ -923,12 +926,12 @@ module.exports = ({ cooler, isPublic }) => {
value: {
timestamp: { $gte: earliest },
content: {
type: "vote"
}
}
}
}
]
type: "vote",
},
},
},
},
],
})
);
const basicSocialFilter = await socialFilter();
@ -937,7 +940,7 @@ module.exports = ({ cooler, isPublic }) => {
pull(
source,
publicOnlyFilter,
pull.filter(msg => {
pull.filter((msg) => {
return (
typeof msg.value.content === "object" &&
typeof msg.value.content.vote === "object" &&
@ -1008,7 +1011,7 @@ module.exports = ({ cooler, isPublic }) => {
}),
// avoid private messages (!) and non-posts
pull.filter(
message =>
(message) =>
message &&
typeof message.value.content !== "string" &&
message.value.content.type === "post"
@ -1038,12 +1041,12 @@ module.exports = ({ cooler, isPublic }) => {
const options = configure({ id: msgId }, customOptions);
return ssb
.get(options)
.then(async rawMsg => {
.then(async (rawMsg) => {
debug("got raw message");
const parents = [];
const getRootAncestor = msg =>
const getRootAncestor = (msg) =>
new Promise((resolve, reject) => {
if (msg.key == null) {
debug("something is very wrong, we used `{ meta: true }`");
@ -1070,9 +1073,9 @@ module.exports = ({ cooler, isPublic }) => {
.get({
id: msg.value.content.fork,
meta: true,
private: true
private: true,
})
.then(fork => {
.then((fork) => {
resolve(getRootAncestor(fork));
})
.catch(reject);
@ -1091,9 +1094,9 @@ module.exports = ({ cooler, isPublic }) => {
.get({
id: msg.value.content.root,
meta: true,
private: true
private: true,
})
.then(root => {
.then((root) => {
resolve(getRootAncestor(root));
})
.catch(reject);
@ -1116,21 +1119,21 @@ module.exports = ({ cooler, isPublic }) => {
}
});
const getReplies = key =>
const getReplies = (key) =>
new Promise((resolve, reject) => {
const filterQuery = {
$filter: {
dest: key
}
dest: key,
},
};
const referenceStream = ssb.backlinks.read({
query: [filterQuery],
index: "DTA" // use asserted timestamps
index: "DTA", // use asserted timestamps
});
pull(
referenceStream,
pull.filter(msg => {
pull.filter((msg) => {
const isPost =
lodash.get(msg, "value.content.type") === "post";
if (isPost === false) {
@ -1164,7 +1167,7 @@ module.exports = ({ cooler, isPublic }) => {
});
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
const flattenDeep = arr1 =>
const flattenDeep = (arr1) =>
arr1.reduce(
(acc, val) =>
Array.isArray(val)
@ -1173,13 +1176,13 @@ module.exports = ({ cooler, isPublic }) => {
[]
);
const getDeepReplies = key =>
const getDeepReplies = (key) =>
new Promise((resolve, reject) => {
const oneDeeper = async (replyKey, depth) => {
const replies = await getReplies(replyKey);
debug(
"replies",
replies.map(m => m.key)
replies.map((m) => m.key)
);
debug("found %s replies for %s", replies.length, replyKey);
@ -1188,7 +1191,7 @@ module.exports = ({ cooler, isPublic }) => {
return replies;
}
return Promise.all(
replies.map(async reply => {
replies.map(async (reply) => {
const deeperReplies = await oneDeeper(reply.key, depth + 1);
lodash.set(reply, "value.meta.thread.depth", depth);
lodash.set(reply, "value.meta.thread.reply", true);
@ -1197,7 +1200,7 @@ module.exports = ({ cooler, isPublic }) => {
);
};
oneDeeper(key, 0)
.then(nested => {
.then((nested) => {
const nestedReplies = [...nested];
const deepReplies = flattenDeep(nestedReplies);
resolve(deepReplies);
@ -1211,7 +1214,7 @@ module.exports = ({ cooler, isPublic }) => {
const deepReplies = await getDeepReplies(rootAncestor.key);
debug("got deep replies");
const allMessages = [rootAncestor, ...deepReplies].map(message => {
const allMessages = [rootAncestor, ...deepReplies].map((message) => {
const isThreadTarget = message.key === msgId;
lodash.set(message, "value.meta.thread.target", isThreadTarget);
return message;
@ -1219,7 +1222,7 @@ module.exports = ({ cooler, isPublic }) => {
return await transform(ssb, allMessages, myFeedId);
})
.catch(err => {
.catch((err) => {
if (err.name === "NotFoundError") {
throw new Error(
"Message not found in the database. You've done nothing wrong. Maybe try again later?"
@ -1243,7 +1246,7 @@ module.exports = ({ cooler, isPublic }) => {
debug("transformed: %O", transformed);
return transformed[0];
},
publish: async options => {
publish: async (options) => {
const ssb = await cooler.open();
const body = { type: "post", ...options };
@ -1269,7 +1272,7 @@ module.exports = ({ cooler, isPublic }) => {
return new Promise((resolve, reject) => {
pull(
pull.values([image]),
ssb.blobs.add(blobId, err => {
ssb.blobs.add(blobId, (err) => {
if (err) {
reject(err);
} else {
@ -1278,7 +1281,7 @@ module.exports = ({ cooler, isPublic }) => {
about: ssb.id,
name,
description,
image: blobId
image: blobId,
};
debug("Published: %O", body);
resolve(ssb.publish(body));
@ -1292,7 +1295,7 @@ module.exports = ({ cooler, isPublic }) => {
return ssb.publish(body);
}
},
publishCustom: async options => {
publishCustom: async (options) => {
const ssb = await cooler.open();
debug("Published: %O", options);
return ssb.publish(options);
@ -1310,7 +1313,7 @@ module.exports = ({ cooler, isPublic }) => {
return post.publish(message);
},
root: async options => {
root: async (options) => {
const message = { type: "post", ...options };
if (isRoot(message) !== true) {
@ -1333,7 +1336,7 @@ module.exports = ({ cooler, isPublic }) => {
if (isPrivate) {
message.recps = lodash
.get(parent, "value.content.recps", [])
.map(recipient => {
.map((recipient) => {
if (
typeof recipient === "object" &&
typeof recipient.link === "string" &&
@ -1379,7 +1382,7 @@ module.exports = ({ cooler, isPublic }) => {
const options = configure(
{
query: [{ $filter: { dest: ssb.id } }]
query: [{ $filter: { dest: ssb.id } }],
},
customOptions
);
@ -1391,12 +1394,12 @@ module.exports = ({ cooler, isPublic }) => {
source,
// Make sure we're only getting private messages that are posts.
pull.filter(
message =>
(message) =>
typeof message.value.content !== "string" &&
lodash.get(message, "value.meta.private") &&
lodash.get(message, "value.content.type") === "post"
),
pull.unique(message => {
pull.unique((message) => {
const { root } = message.value.content;
if (root == null) {
return message.key;
@ -1416,7 +1419,7 @@ module.exports = ({ cooler, isPublic }) => {
});
return messages;
}
},
};
models.post = post;
@ -1430,12 +1433,12 @@ module.exports = ({ cooler, isPublic }) => {
type: "vote",
vote: {
link: messageKey,
value: Number(value)
value: Number(value),
},
branch,
recps
recps,
});
}
},
};
return models;

View File

@ -18,7 +18,7 @@ const remote = `unix:${socketPath}~noauth:${publicInteger}`;
// This is unnecessary when https://github.com/ssbc/ssb-config/pull/72 is merged
ssbConfig.connections.incoming.unix = [
{ scope: "device", transform: "noauth" }
{ scope: "device", transform: "noauth" },
];
const server = flotilla(ssbConfig);
@ -33,7 +33,7 @@ const log = (...args) => {
const rawConnect = () =>
new Promise((resolve, reject) => {
ssbClient(null, { remote })
.then(api => {
.then((api) => {
if (api.tangle === undefined) {
// HACK: SSB-Tangle isn't available in Patchwork, but we want that
// compatibility. This code automatically injects SSB-Tangle into our
@ -53,14 +53,14 @@ const rawConnect = () =>
let handle;
const createConnection = config => {
handle = new Promise(resolve => {
const createConnection = (config) => {
handle = new Promise((resolve) => {
rawConnect()
.then(ssb => {
.then((ssb) => {
log("Using pre-existing Scuttlebutt server instead of starting one");
resolve(ssb);
})
.catch(e => {
.catch((e) => {
if (e.message !== "could not connect to sbot") {
throw e;
}
@ -69,11 +69,11 @@ const createConnection = config => {
server(config);
const connectOrRetry = () => {
rawConnect()
.then(ssb => {
.then((ssb) => {
log("Retrying connection to own server");
resolve(ssb);
})
.catch(e => {
.catch((e) => {
if (e.message !== "could not connect to sbot") {
log(e);
}
@ -98,8 +98,8 @@ module.exports = ({ offline }) => {
const config = {
conn: {
autostart: !offline
}
autostart: !offline,
},
};
createConnection(config);
@ -117,14 +117,14 @@ module.exports = ({ offline }) => {
// If the connection is closed, we need to restart it. It's important to
// note that if we're depending on an external service (like Patchwork) and
// that app is closed, then Oasis will seamlessly start its own SSB service.
return new Promise(resolve => {
handle.then(ssb => {
return new Promise((resolve) => {
handle.then((ssb) => {
if (ssb.closed) {
createConnection();
}
resolve(handle);
});
});
}
},
};
};

View File

@ -7,7 +7,7 @@ module.exports = {
extendedDescription: [
"Posts from ",
strong("people you don't follow"),
", sorted by recency. When you follow someone you may download messages from the people they follow, and those messages show up here."
", sorted by recency. When you follow someone you may download messages from the people they follow, and those messages show up here.",
],
popular: "Popular",
popularDescription: [
@ -15,7 +15,7 @@ module.exports = {
strong("hearts"),
" in a given period. Hearts are counted from ",
em("everyone"),
", including people you don't follow, so this shows posts from your friends that are popular in your extended network."
", including people you don't follow, so this shows posts from your friends that are popular in your extended network.",
],
latest: "Latest",
latestDescription:
@ -23,12 +23,12 @@ module.exports = {
topics: "Topics",
topicsDescription: [
strong("Topics"),
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread."
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread.",
],
summaries: "Summaries",
summariesDescription: [
strong("Topics and some comments"),
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread."
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread.",
],
profile: "Profile",
manualMode: "Manual Mode",
@ -37,13 +37,13 @@ module.exports = {
strong("Posts that mention you"),
" from ",
strong("anyone"),
" sorted by recency. Sometimes people may forget to @mention you, and those posts won't show up here."
" sorted by recency. Sometimes people may forget to @mention you, and those posts won't show up here.",
],
private: "Private",
privateDescription: [
"The latest comment from ",
strong("private threads that include you"),
", sorted by recency. Private posts are encrypted for your public key, and have a maximum of 7 recipients. Recipients cannot be added after the thread has started. Select the timestamp to view the full thread."
", sorted by recency. Private posts are encrypted for your public key, and have a maximum of 7 recipients. Recipients cannot be added after the thread has started. Select the timestamp to view the full thread.",
],
search: "Search",
settings: "Settings",
@ -69,12 +69,12 @@ module.exports = {
publishCustomDescription: [
"Publish a custom message by entering ",
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
" below. This may be useful for prototyping or publishing messages that Oasis doesn't support. This message cannot be edited or deleted."
" below. This may be useful for prototyping or publishing messages that Oasis doesn't support. This message cannot be edited or deleted.",
],
commentWarning: [
" Comments cannot be edited or deleted. To respond to an individual message, select ",
strong("reply"),
" instead."
" instead.",
],
commentPublic: "public",
commentPrivate: "private",
@ -83,28 +83,28 @@ module.exports = {
strong(`${publicOrPrivate} comment`),
" on this thread with ",
a({ href: markdownUrl }, "Markdown"),
"."
".",
],
publishLabel: ({ markdownUrl, linkTarget }) => [
"Write a new public post in ",
a(
{
href: markdownUrl,
target: linkTarget
target: linkTarget,
},
"Markdown"
),
". Posts cannot be edited or deleted."
". Posts cannot be edited or deleted.",
],
publishCustomInfo: ({ href }) => [
"If you're an advanced user, you can also ",
a({ href }, "publish a custom message"),
"."
".",
],
publishBasicInfo: ({ href }) => [
"If you're not an advanced user, you should ",
a({ href }, "publish a post"),
"."
".",
],
publishCustom: "Publish custom",
@ -115,13 +115,13 @@ module.exports = {
a({ href: markdownUrl }, "Markdown"),
". Messages cannot be edited or deleted. To respond to an entire thread, select ",
strong("comment"),
" instead."
" instead.",
],
// settings
settingsIntro: ({ readmeUrl, version }) => [
`You're using Oasis ${version}. Check out `,
a({ href: readmeUrl }, "the readme"),
", configure your theme, or view debugging information below."
", configure your theme, or view debugging information below.",
],
theme: "Theme",
themeIntro:
@ -152,11 +152,11 @@ module.exports = {
// posts and comments
commentDescription: ({ parentUrl }) => [
"commented on ",
a({ href: parentUrl }, " thread")
a({ href: parentUrl }, " thread"),
],
replyDescription: ({ parentUrl }) => [
"replied to ",
a({ href: parentUrl }, " message")
a({ href: parentUrl }, " message"),
],
mysteryDescription: "posted a mysterious message",
// misc
@ -169,7 +169,7 @@ module.exports = {
profileImage: "Profile image",
profileDescription: "Profile description (Markdown)",
hashtagDescription:
"Posts from people in your network that reference this hashtag, sorted by recency."
"Posts from people in your network that reference this hashtag, sorted by recency.",
},
/* spell-checker: disable */
es: {
@ -182,7 +182,7 @@ module.exports = {
extendedDescription: [
"Publicaciones de ",
strong("personas que no seguís"),
", ordenadas por las más recientes. Quando seguís una persona poderás descargar publicaciones de otras personas que esta siga y esos mensajes aparecen aquí."
", ordenadas por las más recientes. Quando seguís una persona poderás descargar publicaciones de otras personas que esta siga y esos mensajes aparecen aquí.",
],
popular: "Populares",
popularDescription: [
@ -190,32 +190,32 @@ module.exports = {
strong("Me Gusta"),
" en determinados periodos. Se cuentan los Me Gusta de ",
em("todos"),
", incluindo aquellos que no seguís. Esta es una lista de publicaciones más populares de tu red de contacto."
", incluindo aquellos que no seguís. Esta es una lista de publicaciones más populares de tu red de contacto.",
],
latestDescription:
"Publicaciones que aquellos que seguís, ordenadas por las más recientes.",
topics: "Topicos",
topicsDescription: [
strong("Topicos"),
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo."
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo.",
],
summaries: "Resumen",
summariesDescription: [
strong("Topicos y algunos comentarios"),
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo."
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo.",
],
manualMode: "Modo manual",
mentions: "Menciones",
mentionsDescription: [
strong("Publicaciones de "),
strong("cualquier persona"),
" que te mencionan, ordenadas por las más recientes. Solo figuran menciones en el formato @mención."
" que te mencionan, ordenadas por las más recientes. Solo figuran menciones en el formato @mención.",
],
private: "Privado",
privateDescription: [
"Los comentarios más recientes de ",
strong("hilos privados que te incluyen"),
". Las publicaciones privadas están encriptadas para tu llave privada, y contienen el máximo de 7 destinatarios. No se podrán adicionar nuevos destinarios después que empieze el hilo. Seleccioná la hora de una publicación para leer el hilo completo."
". Las publicaciones privadas están encriptadas para tu llave privada, y contienen el máximo de 7 destinatarios. No se podrán adicionar nuevos destinarios después que empieze el hilo. Seleccioná la hora de una publicación para leer el hilo completo.",
],
// post actions
comment: "Comentar",
@ -239,12 +239,12 @@ module.exports = {
publishCustomDescription: [
"Compone un mensaje custom usando ",
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
". Esto puede ser util para prototipar o componer tipos de mensaje que Oasis aún no soporta. Este mensaje no podrá ser editado o borrado."
". Esto puede ser util para prototipar o componer tipos de mensaje que Oasis aún no soporta. Este mensaje no podrá ser editado o borrado.",
],
commentWarning: [
" Los mensajes no podrán ser editados o borrados. Para responde a mensajes, seleccione ",
strong("Responder"),
"."
".",
],
commentPublic: "publico",
commentPrivate: "privado",
@ -253,28 +253,28 @@ module.exports = {
strong(`${publicOrPrivate} comentário`),
" con ",
a({ href: markdownUrl }, "Markdown"),
" en este hilo."
" en este hilo.",
],
publishLabel: ({ markdownUrl, linkTarget }) => [
"Escribí mensaje publico con ",
a(
{
href: markdownUrl,
target: linkTarget
target: linkTarget,
},
"Markdown"
),
". Los mensajes no podrán ser editados o borrados."
". Los mensajes no podrán ser editados o borrados.",
],
publishCustomInfo: ({ href }) => [
"Si sos un usário avanzado, podrás ",
a({ href }, "publicar un mensaje custom"),
"."
".",
],
publishBasicInfo: ({ href }) => [
"Si no sos un usuário avanzado, podés ",
a({ href }, "publicar un mensaje basico."),
"."
".",
],
publishCustom: "Publicar custom",
@ -285,13 +285,13 @@ module.exports = {
a({ href: markdownUrl }, "Markdown"),
". Los mensajes no podrán ser editados o borrados. Para responder a todo un hilo, seleccioná ",
strong("comentário"),
"."
".",
],
// settings
settingsIntro: ({ readmeUrl, version }) => [
`Estás usando Oasis ${version}. Leé `,
a({ href: readmeUrl }, "el Readme"),
", configura un tema, o consultá información de debug abajo."
", configura un tema, o consultá información de debug abajo.",
],
theme: "Tema",
themeIntro:
@ -323,11 +323,11 @@ module.exports = {
// posts and comments
commentDescription: ({ parentUrl }) => [
"comentado en el hilo ",
a({ href: parentUrl }, "")
a({ href: parentUrl }, ""),
],
replyDescription: ({ parentUrl }) => [
"respondido al mensaje ",
a({ href: parentUrl }, "")
a({ href: parentUrl }, ""),
],
mysteryDescription: "publicó un mensaje misterioso",
// misc
@ -340,14 +340,14 @@ module.exports = {
profileImage: "Imagen de perfil",
profileDescription: "Descripción de perfil (Markdown)",
hashtagDescription:
"Publicaciones de personas en tu red que mencionan este hashtag, ordenadas por las más recientes."
"Publicaciones de personas en tu red que mencionan este hashtag, ordenadas por las más recientes.",
},
de: {
extended: "Erweitert",
extendedDescription: [
"Beiträge von ",
strong("Leuten denen du nicht folgst"),
", sortiert nach Aktualität. Wenn du jemandem folgst lädst du eventuell auch Beiträge von Leuten herunter denen diese Person folgt, hier erscheinen diese Beiträge."
", sortiert nach Aktualität. Wenn du jemandem folgst lädst du eventuell auch Beiträge von Leuten herunter denen diese Person folgt, hier erscheinen diese Beiträge.",
],
popular: "Beliebt",
popularDescription: [
@ -355,7 +355,7 @@ module.exports = {
strong("Herzen"),
" in der angegebenen Periode. Herzen werden von ",
em("jedem"),
" gezählt, auch von Personen denen du nicht folgst. D.h. hier werden Beiträge von deinen Freund*innen angezeigt die in deinem erweiterten Netzwerk populär sind."
" gezählt, auch von Personen denen du nicht folgst. D.h. hier werden Beiträge von deinen Freund*innen angezeigt die in deinem erweiterten Netzwerk populär sind.",
],
latest: "Aktuell",
latestDescription:
@ -363,12 +363,12 @@ module.exports = {
topics: "Themen",
topicsDescription: [
strong("Themen"),
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen."
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen.",
],
summaries: "Übersicht",
summariesDescription: [
strong("Themen und einige Kommentare"),
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen."
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen.",
],
profile: "Profil",
manualMode: "Manueller Modus",
@ -377,13 +377,13 @@ module.exports = {
strong("Beiträge in denen du erwähnt wirst"),
" von ",
strong("allen"),
", sortiert nach Aktualität. Manchmal vergessen Leute dich zu @erwähnen, diese Beiträge werden hier nicht erscheinen."
", sortiert nach Aktualität. Manchmal vergessen Leute dich zu @erwähnen, diese Beiträge werden hier nicht erscheinen.",
],
private: "Privat",
privateDescription: [
"Die letzten Kommentare aus ",
strong("privaten Threads die dich beinhalten"),
", sortiert nach Aktualität. Private Beiträge werden mit deinem öffentlichen Schlüssel verschlüsselt und haben maximal 7 Empfänger*innen. Empfänger*innen können nicht hinzugefügt werden nachdem ein Thread gestartet wurde. Klicke auf den Zeitstämpel um einen komplette Thread anzuzeigen."
", sortiert nach Aktualität. Private Beiträge werden mit deinem öffentlichen Schlüssel verschlüsselt und haben maximal 7 Empfänger*innen. Empfänger*innen können nicht hinzugefügt werden nachdem ein Thread gestartet wurde. Klicke auf den Zeitstämpel um einen komplette Thread anzuzeigen.",
],
search: "Suche",
settings: "Einstellungen",
@ -409,12 +409,12 @@ module.exports = {
publishCustomDescription: [
"Veröffentliche eine benutzerdefinierte Nachricht durch das Eingeben von ",
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
" unten. Dies kann zum Prototyping oder dem veröffentlichen von Nachrichten die Oasis nicht unterstützt nützlich sein. Diese Nachricht kann nicht bearbeitet oder gelöscht werden."
" unten. Dies kann zum Prototyping oder dem veröffentlichen von Nachrichten die Oasis nicht unterstützt nützlich sein. Diese Nachricht kann nicht bearbeitet oder gelöscht werden.",
],
commentWarning: [
" Nachrichten können nicht bearbeitet oder gelöscht werden. Um auf eine einzelne Nachricht zu antworten, wähle ",
strong("antworten"),
" stattdessen."
" stattdessen.",
],
commentPublic: "öffentlichen",
commentPrivate: "privaten",
@ -423,28 +423,28 @@ module.exports = {
strong(`${publicOrPrivate} Kommentar`),
" in diesem Thread mit ",
a({ href: markdownUrl }, "Markdown"),
"."
".",
],
publishLabel: ({ markdownUrl, linkTarget }) => [
"Verfasse einen neuen öffentlichen Beitrag in ",
a(
{
href: markdownUrl,
target: linkTarget
target: linkTarget,
},
"Markdown"
),
". Beiträge können nicht bearbeitet oder gelöscht werden."
". Beiträge können nicht bearbeitet oder gelöscht werden.",
],
publishCustomInfo: ({ href }) => [
"Wenn du ein erfahrener Benutzer bist kannst du auch ",
a({ href }, "eine benutzerdefinierte Nachricht veröffentlichen"),
"."
".",
],
publishBasicInfo: ({ href }) => [
"Wenn du kein erfahrener Benutzer bist, solltest du ",
a({ href }, "einen einfachen Beitrag veröffentlichen"),
"."
".",
],
publishCustom: "Benutzerdefinierte Veröffentlichung",
replyLabel: ({ markdownUrl }) => [
@ -454,13 +454,13 @@ module.exports = {
a({ href: markdownUrl }, "Markdown"),
". Nachrichten können nicht bearbeitet oder gelöscht werden. Um auf einen kompletten Thread zu antworten, klicke auf ",
strong("kommentieren"),
" stattdessen."
" stattdessen.",
],
// settings
settingsIntro: ({ readmeUrl, version }) => [
`Du verwendest Oasis ${version}. Lese `,
a({ href: readmeUrl }, "die Readme"),
", konfiguriere dein Theme oder schaue dir Debugging-Informationen weiter unten an."
", konfiguriere dein Theme oder schaue dir Debugging-Informationen weiter unten an.",
],
theme: "Theme",
themeIntro:
@ -491,11 +491,11 @@ module.exports = {
// posts and comments
commentDescription: ({ parentUrl }) => [
"kommentierte auf ",
a({ href: parentUrl }, " Thread")
a({ href: parentUrl }, " Thread"),
],
replyDescription: ({ parentUrl }) => [
"antwortete auf ",
a({ href: parentUrl }, " Nachricht")
a({ href: parentUrl }, " Nachricht"),
],
mysteryDescription: "veröffentlichte eine mysteriöse Nachricht",
// misc
@ -507,6 +507,6 @@ module.exports = {
profileName: "Profilname (Text)",
profileDescription: "Profilbeschreibung (Markdown)",
hashtagDescription:
"Beiträge von Leuten in deinem Netzwerk die dieses Hashtag referenzieren, sortiert nach Aktualität."
}
"Beiträge von Leuten in deinem Netzwerk die dieses Hashtag referenzieren, sortiert nach Aktualität.",
},
};

View File

@ -38,7 +38,7 @@ const {
summary,
textarea,
title,
ul
ul,
} = require("hyperaxe");
const lodash = require("lodash");
@ -50,7 +50,7 @@ const i18nBase = require("./i18n");
let i18n = null;
let selectedLanguage = null;
exports.setLanguage = language => {
exports.setLanguage = (language) => {
selectedLanguage = language;
i18n = Object.assign({}, i18nBase.en, i18nBase[language]);
};
@ -60,7 +60,7 @@ const doctypeString = "<!DOCTYPE html>";
const THREAD_PREVIEW_LENGTH = 3;
const toAttributes = obj =>
const toAttributes = (obj) =>
Object.entries(obj)
.map(([key, val]) => `${key}=${val}`)
.join(", ");
@ -83,11 +83,11 @@ const template = (...elements) => {
meta({ charset: "utf-8" }),
meta({
name: "description",
content: i18n.oasisDescription
content: i18n.oasisDescription,
}),
meta({
name: "viewport",
content: toAttributes({ width: "device-width", "initial-scale": 1 })
content: toAttributes({ width: "device-width", "initial-scale": 1 }),
})
),
body(
@ -96,28 +96,28 @@ const template = (...elements) => {
navLink({
href: "/publish",
emoji: "📝",
text: i18n.publish
text: i18n.publish,
}),
navLink({
href: "/public/latest/extended",
emoji: "🗺️",
text: i18n.extended
text: i18n.extended,
}),
navLink({
href: "/public/popular/day",
emoji: "📣",
text: i18n.popular
text: i18n.popular,
}),
navLink({ href: "/public/latest", emoji: "🐇", text: i18n.latest }),
navLink({
href: "/public/latest/topics",
emoji: "📖",
text: i18n.topics
text: i18n.topics,
}),
navLink({
href: "/public/latest/summaries",
emoji: "🗒️",
text: i18n.summaries
text: i18n.summaries,
}),
navLink({ href: "/profile", emoji: "🐱", text: i18n.profile }),
navLink({ href: "/mentions", emoji: "💬", text: i18n.mentions }),
@ -135,11 +135,11 @@ const template = (...elements) => {
return result;
};
const postInAside = msg => {
const postInAside = (msg) => {
const encoded = {
key: encodeURIComponent(msg.key),
author: encodeURIComponent(msg.value.author),
parent: encodeURIComponent(msg.value.content.root)
parent: encodeURIComponent(msg.value.content.root),
};
const url = {
@ -150,7 +150,7 @@ const postInAside = msg => {
avatar: msg.value.meta.author.avatar.url,
json: `/json/${encoded.key}`,
reply: `/reply/${encoded.key}`,
comment: `/comment/${encoded.key}`
comment: `/comment/${encoded.key}`,
};
const isPrivate = Boolean(msg.value.meta.private);
@ -197,16 +197,16 @@ const postInAside = msg => {
post: null,
comment: i18n.commentDescription({ parentUrl: url.parent }),
reply: i18n.replyDescription({ parentUrl: url.parent }),
mystery: i18n.mysteryDescription
mystery: i18n.mysteryDescription,
};
const isMarkdownEmpty = md => md === "<p>undefined</p>\n";
const isMarkdownEmpty = (md) => md === "<p>undefined</p>\n";
const articleElement = isMarkdownEmpty(markdownContent)
? article(
{ class: "content" },
pre({
innerHTML: highlightJs.highlight("json", JSON.stringify(msg, null, 2))
.value
.value,
})
)
: article({ class: "content", innerHTML: markdownContent });
@ -217,7 +217,7 @@ const postInAside = msg => {
return section(
{
class: messageClasses.join(" ")
class: messageClasses.join(" "),
},
header(
span(
@ -244,7 +244,7 @@ const postInAside = msg => {
name: "voteValue",
type: "submit",
value: likeButton.value,
class: likeButton.class
class: likeButton.class,
},
`${likeCount}`
)
@ -267,7 +267,7 @@ const postInAside = msg => {
const continueThreadComponent = (thread, isComment) => {
const encoded = {
next: encodeURIComponent(thread[THREAD_PREVIEW_LENGTH + 1].key),
parent: encodeURIComponent(thread[0].key)
parent: encodeURIComponent(thread[0].key),
};
const left = thread.length - (THREAD_PREVIEW_LENGTH + 1);
let continueLink;
@ -301,7 +301,7 @@ const postAside = ({ key, value }) => {
let postsToShow;
if (isComment) {
const commentPosition = thread.findIndex(msg => msg.key === key);
const commentPosition = thread.findIndex((msg) => msg.key === key);
postsToShow = thread.slice(
commentPosition + 1,
Math.min(commentPosition + (THREAD_PREVIEW_LENGTH + 1), thread.length)
@ -326,7 +326,7 @@ const post = ({ msg, aside = false }) => {
const encoded = {
key: encodeURIComponent(msg.key),
author: encodeURIComponent(msg.value.author),
parent: encodeURIComponent(msg.value.content.root)
parent: encodeURIComponent(msg.value.content.root),
};
const url = {
@ -337,7 +337,7 @@ const post = ({ msg, aside = false }) => {
avatar: msg.value.meta.author.avatar.url,
json: `/json/${encoded.key}`,
reply: `/reply/${encoded.key}`,
comment: `/comment/${encoded.key}`
comment: `/comment/${encoded.key}`,
};
const isPrivate = Boolean(msg.value.meta.private);
@ -390,7 +390,7 @@ const post = ({ msg, aside = false }) => {
post: null,
comment: i18n.commentDescription({ parentUrl: url.parent }),
reply: i18n.replyDescription({ parentUrl: url.parent }),
mystery: i18n.mysteryDescription
mystery: i18n.mysteryDescription,
};
const emptyContent = "<p>undefined</p>\n";
@ -402,7 +402,7 @@ const post = ({ msg, aside = false }) => {
innerHTML: highlightJs.highlight(
"json",
JSON.stringify(msg, null, 2)
).value
).value,
})
)
: article({ class: "content", innerHTML: markdownContent });
@ -415,7 +415,7 @@ const post = ({ msg, aside = false }) => {
{
id: msg.key,
class: messageClasses.join(" "),
style: `margin-left: ${depth}rem;`
style: `margin-left: ${depth}rem;`,
},
header(
span(
@ -454,7 +454,7 @@ const post = ({ msg, aside = false }) => {
name: "voteValue",
type: "submit",
value: likeButton.value,
class: likeButton.class
class: likeButton.class,
},
`${likeCount}`
)
@ -481,7 +481,7 @@ exports.editProfileView = ({ name, description }) =>
{
action: "/profile/edit",
method: "POST",
enctype: "multipart/form-data"
enctype: "multipart/form-data",
},
label(
i18n.profileImage,
@ -493,14 +493,14 @@ exports.editProfileView = ({ name, description }) =>
textarea(
{
autofocus: true,
name: "description"
name: "description",
},
description
)
),
button(
{
type: "submit"
type: "submit",
},
i18n.submit
)
@ -514,7 +514,7 @@ exports.authorView = ({
feedId,
messages,
name,
relationship
relationship,
}) => {
const mention = `[@${name}](${feedId})`;
const markdownMention = highlightJs.highlight("markdown", mention).value;
@ -532,11 +532,11 @@ exports.authorView = ({
: form(
{
action: `/${contactFormType}/${encodeURIComponent(feedId)}`,
method: "post"
method: "post",
},
button(
{
type: "submit"
type: "submit",
},
contactFormType
)
@ -579,7 +579,7 @@ exports.authorView = ({
),
pre({
class: "md-mention",
innerHTML: markdownMention
innerHTML: markdownMention,
}),
description !== "" ? article({ innerHTML: markdown(description) }) : null,
footer(
@ -594,7 +594,7 @@ exports.authorView = ({
return template(
prefix,
messages.map(msg => post({ msg }))
messages.map((msg) => post({ msg }))
);
};
@ -602,7 +602,7 @@ exports.commentView = async ({ messages, myFeedId, parentMessage }) => {
let markdownMention;
const messageElements = await Promise.all(
messages.reverse().map(message => {
messages.reverse().map((message) => {
debug("%O", message);
const authorName = message.value.meta.author.name;
const authorFeedId = message.value.author;
@ -636,13 +636,13 @@ exports.commentView = async ({ messages, myFeedId, parentMessage }) => {
{
autofocus: true,
required: true,
name: "text"
name: "text",
},
isPrivate ? null : markdownMention
),
button(
{
type: "submit"
type: "submit",
},
i18n.comment
)
@ -654,7 +654,7 @@ exports.mentionsView = ({ messages }) => {
return messageListView({
messages,
viewTitle: i18n.mentions,
viewDescription: i18n.mentionsDescription
viewDescription: i18n.mentionsDescription,
});
};
@ -662,7 +662,7 @@ exports.privateView = ({ messages }) => {
return messageListView({
messages,
viewTitle: i18n.private,
viewDescription: i18n.privateDescription
viewDescription: i18n.privateDescription,
});
};
@ -680,7 +680,7 @@ exports.publishCustomView = async () => {
{
autofocus: true,
required: true,
name: "text"
name: "text",
},
"{\n",
' "type": "test",\n',
@ -689,7 +689,7 @@ exports.publishCustomView = async () => {
),
button(
{
type: "submit"
type: "submit",
},
i18n.submit
)
@ -700,7 +700,7 @@ exports.publishCustomView = async () => {
};
exports.threadView = ({ messages }) =>
template(messages.map(msg => post({ msg })));
template(messages.map((msg) => post({ msg })));
exports.markdownView = ({ text }) => {
const rawHtml = md.render(text);
@ -726,7 +726,7 @@ exports.publishView = () => {
name: "contentWarning",
type: "text",
class: "contentWarning",
placeholder: i18n.contentWarningPlaceholder
placeholder: i18n.contentWarningPlaceholder,
})
),
button({ type: "submit" }, i18n.submit)
@ -739,7 +739,7 @@ exports.publishView = () => {
exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
const max = status.sync.since;
const progressElements = Object.entries(status.sync.plugins).map(e => {
const progressElements = Object.entries(status.sync.plugins).map((e) => {
const [key, val] = e;
const id = `progress-${key}`;
return div(label(key, progress({ id, value: val, max }, val)));
@ -763,7 +763,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
const connButtons = div({ class: "form-button-group" }, [
startButton,
restartButton,
stopButton
stopButton,
]);
const peerList = (peers || []).map(([, data]) => {
@ -775,7 +775,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
);
});
const themeElements = themeNames.map(cur => {
const themeElements = themeNames.map((cur) => {
const isCurrentTheme = cur === theme;
if (isCurrentTheme) {
return option({ value: cur, selected: true }, cur);
@ -800,18 +800,18 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
"0C",
"0D",
"0E",
"0F"
"0F",
];
const base16Elements = base16.map(base =>
const base16Elements = base16.map((base) =>
div({
style: {
"background-color": `var(--base${base})`,
width: `${(1 / base16.length) * 100}%`,
height: "1em",
"margin-top": "1em",
display: "inline-block"
}
display: "inline-block",
},
})
);
@ -853,7 +853,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
languageOption("en", "English"),
languageOption("es", "Español"),
/* cspell:disable-next-line */
languageOption("de", "Deutsch")
languageOption("de", "Deutsch"),
]),
button({ type: "submit" }, i18n.setLanguage)
),
@ -882,9 +882,9 @@ exports.likesView = async ({ messages, feed, name }) => {
return template(
viewInfoBox({
viewTitle: span(authorLink, i18n.likedBy)
viewTitle: span(authorLink, i18n.likedBy),
}),
messages.map(msg => post({ msg }))
messages.map((msg) => post({ msg }))
);
};
@ -894,11 +894,11 @@ const messageListView = ({
viewDescription = null,
viewElements = null,
// If `aside = true`, it will show a few comments in the thread.
aside = null
aside = null,
}) => {
return template(
section(h1(viewTitle), p(viewDescription), viewElements),
messages.map(msg => post({ msg, aside }))
messages.map((msg) => post({ msg, aside }))
);
};
@ -907,7 +907,7 @@ exports.popularView = ({ messages, prefix }) => {
messages,
viewElements: prefix,
viewTitle: i18n.popular,
viewDescription: i18n.popularDescription
viewDescription: i18n.popularDescription,
});
};
@ -915,7 +915,7 @@ exports.extendedView = ({ messages }) => {
return messageListView({
messages,
viewTitle: i18n.extended,
viewDescription: i18n.extendedDescription
viewDescription: i18n.extendedDescription,
});
};
@ -923,7 +923,7 @@ exports.latestView = ({ messages }) => {
return messageListView({
messages,
viewTitle: i18n.latest,
viewDescription: i18n.latestDescription
viewDescription: i18n.latestDescription,
});
};
@ -931,7 +931,7 @@ exports.topicsView = ({ messages }) => {
return messageListView({
messages,
viewTitle: i18n.topics,
viewDescription: i18n.topicsDescription
viewDescription: i18n.topicsDescription,
});
};
@ -940,7 +940,7 @@ exports.summaryView = ({ messages }) => {
messages,
viewTitle: i18n.summaries,
viewDescription: i18n.summariesDescription,
aside: true
aside: true,
});
};
@ -952,7 +952,7 @@ exports.replyView = async ({ messages, myFeedId }) => {
let markdownMention;
const messageElements = await Promise.all(
messages.reverse().map(message => {
messages.reverse().map((message) => {
debug("%O", message);
const authorName = message.value.meta.author.name;
const authorFeedId = message.value.author;
@ -975,13 +975,13 @@ exports.replyView = async ({ messages, myFeedId }) => {
{
autofocus: true,
required: true,
name: "text"
name: "text",
},
markdownMention
),
button(
{
type: "submit"
type: "submit",
},
i18n.reply
)
@ -994,7 +994,7 @@ exports.searchView = ({ messages, query }) => {
name: "query",
required: false,
type: "search",
value: query
value: query,
});
// - Minimum length of 3 because otherwise SSB-Search hangs forever. :)
@ -1012,20 +1012,20 @@ exports.searchView = ({ messages, query }) => {
label(i18n.searchLabel, searchInput),
button(
{
type: "submit"
type: "submit",
},
i18n.submit
)
)
),
messages.map(msg => post({ msg }))
messages.map((msg) => post({ msg }))
);
};
exports.hashtagView = ({ messages, hashtag }) => {
return template(
section(h1(`#${hashtag}`), p(i18n.hashtagDescription)),
messages.map(msg => post({ msg }))
messages.map((msg) => post({ msg }))
);
};
@ -1041,11 +1041,11 @@ exports.indexingView = ({ percent }) => {
meta({ charset: "utf-8" }),
meta({
name: "description",
content: i18n.oasisDescription
content: i18n.oasisDescription,
}),
meta({
name: "viewport",
content: toAttributes({ width: "device-width", "initial-scale": 1 })
content: toAttributes({ width: "device-width", "initial-scale": 1 }),
}),
meta({ "http-equiv": "refresh", content: 10 })
),

View File

@ -6,7 +6,7 @@ const ssbRef = require("ssb-ref");
const { span } = require("hyperaxe");
/** @param {{ link: string}[]} mentions */
const toUrl = mentions => {
const toUrl = (mentions) => {
/** @type {{name: string, link: string}[]} */
const mentionNames = [];
@ -21,7 +21,7 @@ const toUrl = mentions => {
ssbMessages.links(mentions, "feed").forEach(handleLink);
/** @param {string} ref */
const urlHandler = ref => {
const urlHandler = (ref) => {
// @mentions
const found = mentionNames.find(({ name }) => name === ref);
if (found !== undefined) {
@ -53,5 +53,5 @@ const toUrl = mentions => {
module.exports = (input, mentions = []) =>
md.block(input, {
toUrl: toUrl(mentions),
emoji: character => span({ class: "emoji" }, character).outerHTML
emoji: (character) => span({ class: "emoji" }, character).outerHTML,
});