initial commit.
This commit is contained in:
commit
b19074b994
|
@ -0,0 +1,12 @@
|
|||
/* eslint-env node */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'plugin:prettier/recommended'
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
root: true
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
dist/*
|
||||
node_modules/*
|
||||
pages/*
|
||||
*.sqlite3
|
||||
.env*
|
|
@ -0,0 +1,19 @@
|
|||
# How to use it
|
||||
|
||||
0. create a dotenv .env
|
||||
1. Create a directory "pages"
|
||||
2. npm install
|
||||
3. npx tsc
|
||||
4. node dist/command.js new-user nickname "fullname"
|
||||
5. create a file pages/whatever-page.md
|
||||
6. node dist/command.js new-article nickname whatever-page "Whatever Page Title"
|
||||
7. node --env-file=.env dist/index.js
|
||||
8. curl --verbose -H 'Accept: application/activity+json' http://127.0.0.1:8080/author/nickname/outbox
|
||||
|
||||
## dotenv contents:
|
||||
|
||||
```
|
||||
blog_host=blog.whatever.example.net
|
||||
blog_title="Your blog title"
|
||||
port=8080
|
||||
```
|
|
@ -0,0 +1,12 @@
|
|||
export default {
|
||||
|
||||
client: "sqlite3",
|
||||
connection: {
|
||||
filename: "./prod.sqlite3"
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
migrations: {
|
||||
directory: "./migrations"
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
export const up = async function (knex) {
|
||||
return knex.schema
|
||||
.createTable("users", (table) => {
|
||||
table.increments("id");
|
||||
table.string("name").notNullable();
|
||||
table.string("nickname").notNullable();
|
||||
table.string("bio");
|
||||
table.boolean("deleted").notNullable();
|
||||
table.timestamps(true, false, false);
|
||||
})
|
||||
.createTable("articles", (table) => {
|
||||
table.increments("id");
|
||||
table.string("title").notNullable();
|
||||
table.string("slug").notNullable().unique();
|
||||
table.string("file").notNullable().unique();
|
||||
table.integer("users_id");
|
||||
table.foreign("users_id").references("users.id").onDelete("CASCADE");
|
||||
table.boolean("deleted").notNullable();
|
||||
table.timestamps(true, false, false);
|
||||
})
|
||||
.createTable("collection_types", (table) => {
|
||||
table.integer("id").unsigned().primary();
|
||||
table.string("name").notNullable();
|
||||
})
|
||||
.createTable("collections", (table) => {
|
||||
table.increments("id");
|
||||
table.integer("collection_types_id").notNullable();
|
||||
table.foreign("collection_types_id").references("collection_types.id");
|
||||
table.integer("articles_id");
|
||||
table.foreign("articles_id").references("articles.id").onDelete("CASCADE");
|
||||
table.integer("users_id");
|
||||
table.foreign("users_id").references("users.id").onDelete("CASCADE");
|
||||
table.string("value").notNullable();
|
||||
})
|
||||
.createTable("outboxes", (table) => {
|
||||
table.increments("id");
|
||||
table.integer("users_id");
|
||||
table.foreign("users_id").references("users.id").onDelete("CASCADE");
|
||||
table.string("verb").notNullable();
|
||||
table.integer("articles_id");
|
||||
table.foreign("articles_id").references("articles.id").onDelete("CASCADE");
|
||||
table.timestamps(true, false, false);
|
||||
})
|
||||
.then(() => {
|
||||
// Hardcoding these so they can be referenced by constants in code.
|
||||
knex("collection_types").insert([
|
||||
{
|
||||
id: 0,
|
||||
name: "followers"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: "likes"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "announcements"
|
||||
}
|
||||
]);
|
||||
});
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
export const down = function (knex) {
|
||||
return knex.schema
|
||||
.dropTableIfExists("outboxes")
|
||||
.dropTableIfExists("collections")
|
||||
.dropTableIfExists("collection_types")
|
||||
.dropTableIfExists("articles")
|
||||
.dropTableIfExists("users")
|
||||
;
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
declare module "activitypub-express" {
|
||||
function ActivitypubExpress(options: Record<string, any>);
|
||||
export default ActivitypubExpress;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "activitypress",
|
||||
"version": "1.0.0",
|
||||
"description": "Activitypub-enabled Markdown blog",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"new-migration": "npx knex --migrations-directory migrations --esm migrate:make"
|
||||
},
|
||||
"keywords": [
|
||||
"blog",
|
||||
"activitypub",
|
||||
"markdown"
|
||||
],
|
||||
"author": "moon@shipoclu.com",
|
||||
"license": "AGPL-3.0",
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/markdown-it": "^13.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||
"@typescript-eslint/parser": "^6.15.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.1",
|
||||
"prettier": "3.1.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"activitypub-express": "^4.4.1",
|
||||
"better-sqlite3": "^9.2.2",
|
||||
"knex": "^3.1.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"sqlite3": "^5.1.6",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import db from "./db.js";
|
||||
import { z } from "zod";
|
||||
|
||||
export const slugRegex = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
export const zArticle = z.object({
|
||||
id: z.number().min(0),
|
||||
title: z.string().min(1),
|
||||
slug: z.string().regex(slugRegex).min(3).max(100),
|
||||
file: z.string().regex(/^[a-zA-Z0-9_-]+\.md$/),
|
||||
users_id: z.number().min(0),
|
||||
deleted: z.boolean(),
|
||||
created_at: z.date(),
|
||||
updated_at: z.union([z.date(), z.null()])
|
||||
});
|
||||
|
||||
export type Article = z.infer<typeof zArticle>;
|
||||
|
||||
export const getBySlug = async (slug: string): Promise<Article | null> => {
|
||||
return db<Article>("articles")
|
||||
.where("slug", slug)
|
||||
.first()
|
||||
.then((rec) => !!rec ? rec : null)
|
||||
};
|
||||
|
||||
export const getById = async (articleId: number): Promise<Article | null> => {
|
||||
return db<Article>("articles")
|
||||
.where("id", articleId)
|
||||
.first()
|
||||
.then((rec) => !!rec ? rec : null)
|
||||
};
|
||||
|
||||
export const insert = async (userId: number, slug: string, title: string): Promise<number> => {
|
||||
return db("articles").insert({
|
||||
users_id: userId,
|
||||
slug,
|
||||
title,
|
||||
file: `pages/${slug}.md`,
|
||||
deleted: false,
|
||||
created_at: new Date()
|
||||
})
|
||||
.returning("id")
|
||||
.then(([{ id: id }]: { id: number }[]) => id)
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
import fs from "node:fs";
|
||||
import markdownit from 'markdown-it'
|
||||
import { slugRegex } from "./article.js";
|
||||
import { newUser, getId as getUserIdByNickname } from "./user.js";
|
||||
import { insert as insertArticle } from "./article.js";
|
||||
import { add as addToOutbox } from "./outbox.js";
|
||||
|
||||
const md = markdownit();
|
||||
|
||||
const c = process.argv[2];
|
||||
let returnCode = 0;
|
||||
|
||||
if (c === "new-user") {
|
||||
const nickname = process.argv[3];
|
||||
const name = process.argv[4];
|
||||
const bio = process.argv[5] || "";
|
||||
const userId = await newUser(nickname, name, bio);
|
||||
console.log(userId);
|
||||
}
|
||||
else if (c === "new-article") {
|
||||
const nickname = process.argv[3];
|
||||
const slug = process.argv[4];
|
||||
const title = process.argv[5];
|
||||
const images = process.argv.slice(6);
|
||||
|
||||
const userId = await getUserIdByNickname(nickname);
|
||||
if (!userId) {
|
||||
console.error("Nonexistent user");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!slugRegex.test(slug)) {
|
||||
returnCode = 1;
|
||||
console.error("Bad slug");
|
||||
process.exit(returnCode);
|
||||
}
|
||||
|
||||
const filename = `pages/${slug}.md`;
|
||||
if (!fs.existsSync(filename)) {
|
||||
console.error("No file with that slug");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const htmlFilename = `pages/${slug}.html`;
|
||||
const markdown = fs.readFileSync(filename, "utf-8");
|
||||
const html = md.render(markdown);
|
||||
fs.writeFileSync(htmlFilename, html);
|
||||
|
||||
const articleId = await insertArticle(userId, slug, title);
|
||||
console.log(articleId);
|
||||
|
||||
await addToOutbox(articleId);
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
else {
|
||||
console.error("Unrecognized command: ", c);
|
||||
returnCode = 1;
|
||||
|
||||
process.exit(returnCode);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import knex from "knex";
|
||||
import config from "./knexfile.js";
|
||||
|
||||
const db = knex(config);
|
||||
|
||||
export default db;
|
|
@ -0,0 +1,72 @@
|
|||
import express from "express";
|
||||
import ActivitypubExpress from "activitypub-express";
|
||||
import { get as getOutbox } from "./outbox.js";
|
||||
|
||||
const port = parseInt(process.env.port || "8080");
|
||||
const app = express();
|
||||
|
||||
export const routes = {
|
||||
actor: "/author/:actor",
|
||||
object: "/o/:id",
|
||||
activity: "/a/:id",
|
||||
inbox: "/author/:actor/inbox",
|
||||
outbox: "/author/:actor/outbox",
|
||||
followers: "/author/:actor/followers",
|
||||
following: "/author/:actor/following",
|
||||
liked: "/author/:actor/liked",
|
||||
collections: "/author/:actor/c/:id",
|
||||
blocked: "/author/:actor/blocked",
|
||||
rejections: "/author/:actor/rejections",
|
||||
rejected: "/author/:actor/rejected",
|
||||
shares: "/a/:id/shares",
|
||||
likes: "/a/:id/likes",
|
||||
} as const;
|
||||
|
||||
const SITE = ActivitypubExpress({
|
||||
name: process.env.BLOG_NAME,
|
||||
version: "1.0.0",
|
||||
domain: process.env.BLOG_DOMAIN,
|
||||
actorParam: "actor",
|
||||
objectParam: "id",
|
||||
activityParam: "id",
|
||||
routes,
|
||||
endpoints: {
|
||||
proxyUrl: "https://localhost/proxy",
|
||||
},
|
||||
});
|
||||
|
||||
app.use(
|
||||
express.json({ type: SITE.consts.jsonldTypes }),
|
||||
express.urlencoded({ extended: true }),
|
||||
SITE,
|
||||
);
|
||||
|
||||
app.route(routes.inbox).get(SITE.net.inbox.get).post(SITE.net.inbox.post);
|
||||
// app.route(routes.outbox).get(SITE.net.outbox.get).post(SITE.net.outbox.post);
|
||||
app.get(routes.actor, SITE.net.actor.get);
|
||||
app.get(routes.followers, SITE.net.followers.get);
|
||||
app.get(routes.following, SITE.net.following.get);
|
||||
app.get(routes.liked, SITE.net.liked.get);
|
||||
app.get(routes.object, SITE.net.object.get);
|
||||
app.get(routes.activity, SITE.net.activityStream.get);
|
||||
app.get(routes.shares, SITE.net.shares.get);
|
||||
app.get(routes.likes, SITE.net.likes.get);
|
||||
app.get("/.well-known/webfinger", SITE.net.webfinger.get);
|
||||
app.get("/.well-known/nodeinfo", SITE.net.nodeInfoLocation.get);
|
||||
app.get("/nodeinfo/:version", SITE.net.nodeInfo.get);
|
||||
app.post("/proxy", SITE.net.proxy.post);
|
||||
|
||||
app.get(routes.outbox, async (req, res) => {
|
||||
const nickname = req.params.actor;
|
||||
const body = await getOutbox(nickname).then((out) => JSON.stringify(out, null, 4));
|
||||
res.append("Content-Type", "application/activity+json");
|
||||
res.send(body);
|
||||
});
|
||||
|
||||
app.get("/:slug", (req, res) => {
|
||||
});
|
||||
|
||||
app.get("/:slug.md", (req, res) => {
|
||||
});
|
||||
|
||||
const SERVER = app.listen(port);
|
|
@ -0,0 +1,13 @@
|
|||
export default {
|
||||
|
||||
client: "sqlite3",
|
||||
connection: {
|
||||
filename: "./prod.sqlite3"
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
migrations: {
|
||||
directory: "./migrations"
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import db from "./db.js";
|
||||
import { z } from "zod";
|
||||
import { getId as getUserId, getActor } from "./user.js";
|
||||
import { routes } from "./index.js";
|
||||
import { getById as getArticleById } from "./article.js";
|
||||
|
||||
|
||||
export const zRawOutboxRecord = z.object({
|
||||
id: z.number().min(0),
|
||||
users_id: z.number().min(0),
|
||||
verb: z.string().regex(/^[a-zA-Z]+$/).min(1),
|
||||
articles_id: z.number().min(0),
|
||||
created_at: z.date(),
|
||||
updated_at: z.union([z.date(), z.null()]),
|
||||
slug: z.optional(z.string()),
|
||||
file: z.optional(z.string()),
|
||||
title: z.optional(z.string())
|
||||
});
|
||||
|
||||
export type RawOutboxRecord = z.infer<typeof zRawOutboxRecord>;
|
||||
|
||||
export const get = async (nickname: string): Promise<Record<string, any> | null> => {
|
||||
const userId = await getUserId(nickname);
|
||||
|
||||
if (userId) {
|
||||
const actor = getActor(nickname);
|
||||
|
||||
const ret = db<RawOutboxRecord>("outboxes")
|
||||
.select("outboxes.*", "slug", "file", "title")
|
||||
.join("articles", "outboxes.articles_id", "=", "articles.id")
|
||||
.where("outboxes.users_id", userId)
|
||||
.orderBy("created_at", "desc")
|
||||
.then((recs: RawOutboxRecord[]) => {
|
||||
const activities: Record<string, any>[] = recs.map((rec) => {
|
||||
const published = typeof rec.created_at === "number" ? new Date(rec.created_at) : rec.created_at;
|
||||
const canonicalUrl = `https://${process.env.blog_host}/${rec.slug}.html`;
|
||||
const context = `https://${process.env.blog_host}/c/${rec.articles_id}`;
|
||||
const followers = `https://${process.env.blog_host}${routes.followers.replace(":actor", nickname)}`;
|
||||
const activity: Record<string, any> = {
|
||||
id: `https://${process.env.blog_host}${routes.activity.replace(":id", rec.id.toString())}`,
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
type: rec.verb,
|
||||
actor,
|
||||
context,
|
||||
to: ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
cc: [followers],
|
||||
published
|
||||
};
|
||||
|
||||
const objectId = `https://${process.env.blog_host}${routes.object.replace(":id", rec.articles_id.toString())}`;
|
||||
const content = readFileSync(rec.file as string, "utf-8");
|
||||
activity.object = {
|
||||
id: objectId,
|
||||
actor,
|
||||
attributedTo: actor,
|
||||
type: "Article",
|
||||
context,
|
||||
content,
|
||||
to: ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
cc: [followers],
|
||||
url: canonicalUrl,
|
||||
mediaType: "text/markdown",
|
||||
published
|
||||
};
|
||||
|
||||
return activity;
|
||||
});
|
||||
|
||||
const collection = {
|
||||
type: "OrderedCollectionPage",
|
||||
context: "https://www.w3.org/ns/activitystreams",
|
||||
id: `https://${process.env.blog_host}${routes.outbox.replace(":actor", nickname)}`,
|
||||
orderedItems: activities
|
||||
};
|
||||
|
||||
return collection;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const add = async (articleId: number): Promise<number> => {
|
||||
const article = await getArticleById(articleId);
|
||||
|
||||
if (article) {
|
||||
return await db("outboxes").insert({
|
||||
users_id: article.id,
|
||||
verb: "Create",
|
||||
articles_id: articleId,
|
||||
created_at: article.created_at
|
||||
})
|
||||
.returning("id")
|
||||
.then(([{ id: id }]: { id: number }[]) => id)
|
||||
|
||||
}
|
||||
else throw "failed to add to outbox";
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
import db from "./db.js";
|
||||
import { z } from "zod";
|
||||
import { routes } from "./index.js";
|
||||
|
||||
export const nicknameRegex = /^[a-zA-Z0-9_]+$/;
|
||||
|
||||
export const zUser = z.object({
|
||||
id: z.number().min(0),
|
||||
name: z.string().min(1),
|
||||
nickname: z.string().regex(nicknameRegex),
|
||||
bio: z.string(),
|
||||
deleted: z.boolean(),
|
||||
created_at: z.date(),
|
||||
updated_at: z.union([z.date(), z.null()])
|
||||
});
|
||||
|
||||
export type User = z.infer<typeof zUser>;
|
||||
|
||||
export const getActor = (nickname: string) =>
|
||||
"https://"
|
||||
+ process.env.blog_host
|
||||
+ routes.actor.replace(":actor", nickname);
|
||||
|
||||
export const getNickname = async (userId: number): Promise<string | null> =>
|
||||
db("users")
|
||||
.select("nickname")
|
||||
.where("id", userId)
|
||||
.first()
|
||||
.then((rec) => !!rec ? rec.nickname : null)
|
||||
;
|
||||
|
||||
export const getId = async (nickname: string): Promise<number | null> =>
|
||||
db("users")
|
||||
.select("id")
|
||||
.where("nickname", nickname)
|
||||
.first()
|
||||
.then((rec) => !!rec ? rec.id : null)
|
||||
;
|
||||
|
||||
export const newUser = async (nickname: string, name: string, bio: string): Promise<number> => {
|
||||
return db("users")
|
||||
.insert({
|
||||
name,
|
||||
nickname,
|
||||
bio,
|
||||
deleted: false,
|
||||
created_at: new Date()
|
||||
})
|
||||
.returning("id")
|
||||
.then(([{ id: id }]: { id: number }[]) => id)
|
||||
;
|
||||
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "ESNext", /* Specify what module code is generated. */
|
||||
"rootDir": "./src", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue