mdts 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <link rel="stylesheet" href="/markdown.css" />
8
8
  <title>mdts - Markdown file viewer</title>
9
- </head>
9
+ <script defer src="bundle.js"></script></head>
10
10
  <body>
11
11
  <div id="root"></div>
12
12
  <script defer src="/bundle.js"></script>
package/dist/index.js CHANGED
@@ -1,2 +1,4 @@
1
- import { cli } from './cli.js';
2
- cli();
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const cli_1 = require("./cli");
4
+ new cli_1.CLI().run();
@@ -0,0 +1,32 @@
1
+ <svg width="300" height="100" viewBox="0 0 180 100" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="grad" x1="0" y1="0" x2="1" y2="1">
4
+ <stop offset="0%" stop-color="#1b294a"/>
5
+ <stop offset="100%" stop-color="#1f43ab"/>
6
+ </linearGradient>
7
+ <style>
8
+ .text {
9
+ font-family: 'Segoe UI', 'Arial', sans-serif;
10
+ font-size: 42px;
11
+ font-weight: 700;
12
+ fill: url(#grad);
13
+ letter-spacing: 2px;
14
+ }
15
+ .icon {
16
+ fill: url(#grad);
17
+ }
18
+ </style>
19
+ </defs>
20
+
21
+ <!-- Icon (Abstract Folder Tree) -->
22
+ <g class="icon" transform="translate(10, 20)">
23
+ <path d="M5 25 L15 45" stroke="url(#grad)" stroke-width="2"/>
24
+ <path d="M25 25 L15 45" stroke="url(#grad)" stroke-width="2"/>
25
+ <rect x="0" y="20" width="10" height="10" rx="2"/>
26
+ <rect x="20" y="20" width="10" height="10" rx="2"/>
27
+ <rect x="10" y="40" width="10" height="10" rx="2"/>
28
+ </g>
29
+
30
+ <!-- Logotype -->
31
+ <text x="60" y="70" class="text">mdts</text>
32
+ </svg>
@@ -1,5 +1,5 @@
1
1
  <h1 align="center">
2
- <img src="logo.svg" alt="mdts" width="400">
2
+ <img src="./logo.svg" alt="mdts" width="400">
3
3
  </h1>
4
4
 
5
5
  mdts (Markdown Tree Server) is a simple and efficient tool for serving and viewing markdown files with an interactive file tree and outline. It's designed to help you navigate and read your markdown-based documentation or notes with ease.
@@ -1,6 +1,12 @@
1
- import { Router } from 'express';
2
- import fs from 'fs';
3
- import path from 'path';
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fileTreeRouter = void 0;
7
+ const express_1 = require("express");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
4
10
  const isDotFileOrDirectory = (entryName) => {
5
11
  return entryName.startsWith('.');
6
12
  };
@@ -9,11 +15,11 @@ const isLibraryDirectory = (entryName) => {
9
15
  return libraryDirs.includes(entryName);
10
16
  };
11
17
  const getFileTree = (baseDirectory, currentRelativePath) => {
12
- const entries = fs.readdirSync(path.join(baseDirectory, currentRelativePath), { withFileTypes: true })
18
+ const entries = fs_1.default.readdirSync(path_1.default.join(baseDirectory, currentRelativePath), { withFileTypes: true })
13
19
  .filter(entry => !isDotFileOrDirectory(entry.name) && !isLibraryDirectory(entry.name));
14
20
  const tree = [];
15
21
  for (const entry of entries) {
16
- const entryPath = path.join(currentRelativePath, entry.name);
22
+ const entryPath = path_1.default.join(currentRelativePath, entry.name);
17
23
  if (entry.isDirectory()) {
18
24
  const subTree = getFileTree(baseDirectory, entryPath);
19
25
  if (subTree.length > 0) { // Only include directory if it contains markdown files
@@ -26,10 +32,11 @@ const getFileTree = (baseDirectory, currentRelativePath) => {
26
32
  }
27
33
  return tree;
28
34
  };
29
- export const fileTreeRouter = (directory) => {
30
- const router = Router();
35
+ const fileTreeRouter = (directory) => {
36
+ const router = (0, express_1.Router)();
31
37
  router.get('/', (req, res) => {
32
38
  res.json(getFileTree(directory, ''));
33
39
  });
34
40
  return router;
35
41
  };
42
+ exports.fileTreeRouter = fileTreeRouter;
@@ -1,11 +1,14 @@
1
- import { Router } from 'express';
2
- import fs from 'fs';
3
- import MarkdownIt from 'markdown-it';
4
- import path, { dirname } from 'path';
5
- import { fileURLToPath } from 'url';
6
- const md = new MarkdownIt();
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = dirname(__filename);
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.outlineRouter = void 0;
7
+ const express_1 = require("express");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const markdown_it_1 = __importDefault(require("markdown-it"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const md = new markdown_it_1.default();
9
12
  const slugify = (text) => {
10
13
  return text
11
14
  .toLowerCase()
@@ -15,7 +18,7 @@ const slugify = (text) => {
15
18
  .replace(/^-+|-+$/g, ''); // Trim leading/trailing hyphens
16
19
  };
17
20
  const getMarkdownOutline = (filePath) => {
18
- const fileContent = fs.readFileSync(filePath, 'utf-8');
21
+ const fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
19
22
  const tokens = md.parse(fileContent, {});
20
23
  const outline = [];
21
24
  for (const token of tokens) {
@@ -31,8 +34,8 @@ const getMarkdownOutline = (filePath) => {
31
34
  }
32
35
  return outline;
33
36
  };
34
- export const outlineRouter = (directory) => {
35
- const router = Router();
37
+ const outlineRouter = (directory) => {
38
+ const router = (0, express_1.Router)();
36
39
  router.get('/', (req, res) => {
37
40
  const filePath = req.query.filePath;
38
41
  if (!filePath) {
@@ -40,8 +43,8 @@ export const outlineRouter = (directory) => {
40
43
  }
41
44
  try {
42
45
  const absolutePath = filePath === 'mdts-welcome-markdown.md'
43
- ? path.join(__dirname, '../../../public/welcome.md')
44
- : path.join(directory, filePath);
46
+ ? path_1.default.join(__dirname, '../../../public/welcome.md')
47
+ : path_1.default.join(directory, filePath);
45
48
  const outline = getMarkdownOutline(absolutePath);
46
49
  res.json(outline);
47
50
  }
@@ -52,3 +55,4 @@ export const outlineRouter = (directory) => {
52
55
  });
53
56
  return router;
54
57
  };
58
+ exports.outlineRouter = outlineRouter;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -7,51 +8,65 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
9
  });
9
10
  };
10
- import chokidar from 'chokidar';
11
- import express from 'express';
12
- import { promises as fs } from 'fs';
13
- import path, { dirname } from 'path';
14
- import { fileURLToPath } from 'url';
15
- import { WebSocketServer } from 'ws';
16
- import { fileTreeRouter } from './routes/filetree.js';
17
- import { outlineRouter } from './routes/outline.js';
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = dirname(__filename);
20
- export const serve = (directory, port) => {
21
- const app = express();
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createApp = exports.serve = void 0;
16
+ const chokidar_1 = __importDefault(require("chokidar"));
17
+ const express_1 = __importDefault(require("express"));
18
+ const fs_1 = require("fs");
19
+ const path_1 = __importDefault(require("path"));
20
+ const ws_1 = require("ws");
21
+ const filetree_1 = require("./routes/filetree");
22
+ const outline_1 = require("./routes/outline");
23
+ const serve = (directory, port) => {
24
+ const app = (0, exports.createApp)(directory);
25
+ const server = app.listen(port, () => {
26
+ console.log(`🚀 Server listening at http://localhost:${port}`);
27
+ });
28
+ setupWatcher(directory, server);
29
+ return server;
30
+ };
31
+ exports.serve = serve;
32
+ const createApp = (directory, currentLocation = __dirname) => {
33
+ const app = (0, express_1.default)();
22
34
  // Mount library static files
23
- app.use(express.static(path.join(__dirname, '../../public')));
24
- app.use(express.static(path.join(__dirname, '../../dist/frontend')));
35
+ app.use(express_1.default.static(path_1.default.join(currentLocation, './public')));
36
+ app.use(express_1.default.static(path_1.default.join(currentLocation, '../frontend')));
25
37
  // Define API
26
- app.use('/api/filetree', fileTreeRouter(directory));
38
+ app.use('/api/filetree', (0, filetree_1.fileTreeRouter)(directory));
39
+ app.use('/api/outline', (0, outline_1.outlineRouter)(directory));
27
40
  app.get('/api/markdown/mdts-welcome-markdown.md', (req, res) => {
28
41
  res.setHeader('Content-Type', 'text/plain');
29
- res.sendFile(path.join(__dirname, '../../public/welcome.md'));
42
+ res.sendFile(path_1.default.join(currentLocation, './public/welcome.md'));
30
43
  });
31
- app.use('/api/markdown', express.static(directory));
32
- app.use('/api/outline', outlineRouter(directory));
44
+ app.use('/api/markdown', express_1.default.static(directory));
33
45
  // Catch-all route to serve index.html for any other requests
34
46
  app.get('*', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
35
- const filePath = path.join(directory, req.path);
47
+ const filePath = path_1.default.join(directory, req.path);
36
48
  let isDirectory = false;
37
49
  try {
38
- const stats = yield fs.stat(filePath);
50
+ const stats = yield fs_1.promises.stat(filePath);
39
51
  isDirectory = stats.isDirectory();
40
52
  }
41
- catch (error) {
53
+ catch (_a) {
42
54
  // File or directory does not exist, proceed as if it's a file
43
55
  }
44
- if (isDirectory || req.path.toLowerCase().endsWith('.md') || req.path.toLowerCase().endsWith('.markdown')) {
45
- return res.sendFile(path.join(__dirname, '../../public/index.html'));
56
+ if (isDirectory ||
57
+ req.path.toLowerCase().endsWith('.md') ||
58
+ req.path.toLowerCase().endsWith('.markdown')) {
59
+ return res.sendFile(path_1.default.join(currentLocation, '../frontend/index.html'));
46
60
  }
47
61
  else {
48
62
  return res.sendFile(req.path, { root: directory });
49
63
  }
50
64
  }));
51
- const server = app.listen(port, () => {
52
- console.log(`🚀 Server listening at http://localhost:${port}`);
53
- });
54
- const wss = new WebSocketServer({ server });
65
+ return app;
66
+ };
67
+ exports.createApp = createApp;
68
+ const setupWatcher = (directory, server) => {
69
+ const wss = new ws_1.WebSocketServer({ server });
55
70
  const isMarkdownOrSimpleAsset = (filePath) => {
56
71
  const ext = filePath.toLowerCase().split('.').pop();
57
72
  return (ext &&
@@ -65,18 +80,18 @@ export const serve = (directory, port) => {
65
80
  };
66
81
  let watcher;
67
82
  try {
68
- watcher = chokidar.watch(directory, {
69
- ignored: (filePath) => {
70
- if (filePath.includes('node_modules')) {
83
+ watcher = chokidar_1.default.watch(directory, {
84
+ ignored: (watchedFilePath) => {
85
+ if (watchedFilePath.includes('node_modules')) {
71
86
  return true;
72
87
  }
73
- return !isMarkdownOrSimpleAsset(filePath);
88
+ return !isMarkdownOrSimpleAsset(watchedFilePath);
74
89
  },
75
90
  ignoreInitial: true,
76
91
  });
77
92
  }
78
- catch (error) {
79
- console.error('🚫 Error watching directory:', error);
93
+ catch (e) {
94
+ console.error('🚫 Error watching directory:', e);
80
95
  console.error('Livereload will be disabled');
81
96
  }
82
97
  watcher === null || watcher === void 0 ? void 0 : watcher.on('change', (filePath) => {
@@ -92,7 +107,7 @@ export const serve = (directory, port) => {
92
107
  });
93
108
  });
94
109
  watcher === null || watcher === void 0 ? void 0 : watcher.on('unlink', (filePath) => {
95
- console.log('🌲 File removed: ${filePath}, reloading tree...');
110
+ console.log(`🌲 File removed: ${filePath}, reloading tree...`);
96
111
  wss.clients.forEach((client) => {
97
112
  client.send(JSON.stringify({ type: 'reload-tree' }));
98
113
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdts",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "A markdown preview server.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,14 +8,16 @@
8
8
  "mdts": "./bin/mdts"
9
9
  },
10
10
  "files": [
11
- "dist",
12
- "public"
11
+ "dist"
13
12
  ],
14
13
  "scripts": {
15
- "test": "echo \"Error: no test specified\" && exit 1",
16
- "build": "tsc",
17
- "build:frontend": "webpack --config webpack.config.js",
18
- "start": "npm run build:frontend && npm run build && node dist/index.js"
14
+ "build": "tsc && cp -R public/. dist/server/public",
15
+ "build:frontend": "cd packages/frontend && npm run build && cp -R dist/. ../../dist/frontend",
16
+ "jest": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.config.js",
17
+ "watch": "npm run jest -- --watch",
18
+ "test": "npm run jest -- --selectProjects test",
19
+ "lint": "npm run jest -- --selectProjects lint",
20
+ "start": "npm run build && npm run build:frontend && node dist/index.js"
19
21
  },
20
22
  "repository": {
21
23
  "type": "git",
@@ -30,49 +32,35 @@
30
32
  ],
31
33
  "author": "unhappychoice",
32
34
  "license": "MIT",
33
- "type": "module",
34
35
  "bugs": {
35
36
  "url": "https://github.com/unhappychoice/mdts/issues"
36
37
  },
37
38
  "homepage": "https://github.com/unhappychoice/mdts#readme",
38
39
  "devDependencies": {
39
- "@babel/core": "^7.28.0",
40
- "@babel/preset-env": "^7.28.0",
41
- "@babel/preset-react": "^7.27.1",
42
- "@babel/preset-typescript": "^7.27.1",
43
- "@emotion/react": "^11.11.4",
44
- "@emotion/styled": "^11.11.5",
45
- "@mui/material": "^7.2.0",
46
40
  "@types/commander": "^2.12.0",
47
41
  "@types/express": "^4.17.21",
42
+ "@types/jest": "^30.0.0",
48
43
  "@types/markdown-it": "^14.1.2",
49
- "@types/react": "^19.1.8",
50
- "@types/react-dom": "^19.1.6",
44
+ "@types/supertest": "^6.0.3",
51
45
  "@types/ws": "^8.18.1",
52
- "babel-loader": "^10.0.0",
53
- "css-loader": "^7.1.2",
54
- "html-webpack-plugin": "^5.6.3",
55
- "style-loader": "^4.0.0",
46
+ "@typescript-eslint/eslint-plugin": "^8.37.0",
47
+ "@typescript-eslint/parser": "^8.37.0",
48
+ "axios": "^1.10.0",
49
+ "eslint": "^8.0.0",
50
+ "jest": "^30.0.4",
51
+ "jest-runner-eslint": "^2.3.0",
52
+ "open": "^10.2.0",
53
+ "supertest": "^7.1.3",
54
+ "ts-jest": "^29.4.0",
56
55
  "ts-node": "^10.9.2",
57
56
  "typescript": "^5.8.3",
58
- "webpack": "^5.100.1",
59
- "webpack-cli": "^6.0.1"
57
+ "typescript-eslint": "^8.37.0"
60
58
  },
61
59
  "dependencies": {
62
- "@mui/icons-material": "^7.2.0",
63
- "@mui/x-tree-view": "^8.8.0",
64
60
  "chokidar": "^4.0.3",
65
61
  "commander": "^14.0.0",
66
62
  "express": "^4.19.2",
67
63
  "markdown-it": "^14.1.0",
68
- "open": "^10.1.2",
69
- "react": "^19.1.0",
70
- "react-dom": "^19.1.0",
71
- "react-markdown": "^10.1.0",
72
- "remark-gfm": "^4.0.1",
73
- "remark-slug": "^7.0.1",
74
- "rehype-raw": "^7.0.0",
75
- "react-syntax-highlighter": "^15.6.1",
76
64
  "ws": "^8.18.3"
77
65
  }
78
66
  }
File without changes
File without changes
File without changes