sdocs-dev 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/sdocs-dev.js +443 -0
- package/package.json +40 -0
- package/public/css/layout.css +237 -0
- package/public/css/mobile.css +189 -0
- package/public/css/panel.css +348 -0
- package/public/css/rendered.css +278 -0
- package/public/css/tokens.css +112 -0
- package/public/css/write.css +128 -0
- package/public/default.md +129 -0
- package/public/index.html +533 -0
- package/public/sdocs-app.js +595 -0
- package/public/sdocs-controls.js +221 -0
- package/public/sdocs-export.js +193 -0
- package/public/sdocs-state.js +43 -0
- package/public/sdocs-styles.js +285 -0
- package/public/sdocs-theme.js +168 -0
- package/public/sdocs-write.js +737 -0
- package/public/sdocs-yaml.js +78 -0
- package/server.js +65 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// sdocs-yaml.js — YAML front matter parse/serialize (UMD)
|
|
2
|
+
// Shared by browser (app) and Node (CLI + tests)
|
|
3
|
+
(function (exports) {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
function parseScalar(v) {
|
|
7
|
+
v = v.trim().replace(/^["']|["']$/g, '');
|
|
8
|
+
const n = Number(v);
|
|
9
|
+
return (!isNaN(n) && v !== '') ? n : v;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function parseInlineObject(str) {
|
|
13
|
+
const inner = str.replace(/^\{/, '').replace(/\}$/, '').trim();
|
|
14
|
+
const obj = {};
|
|
15
|
+
inner.split(',').forEach(pair => {
|
|
16
|
+
const m = pair.trim().match(/^(\w[\w-]*):\s*(.*)/);
|
|
17
|
+
if (m) obj[m[1]] = parseScalar(m[2].trim());
|
|
18
|
+
});
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseSimpleYaml(str) {
|
|
23
|
+
const result = {};
|
|
24
|
+
const lines = str.split('\n');
|
|
25
|
+
let i = 0;
|
|
26
|
+
while (i < lines.length) {
|
|
27
|
+
const line = lines[i];
|
|
28
|
+
const km = line.match(/^(\w[\w-]*):\s*(.*)/);
|
|
29
|
+
if (!km) { i++; continue; }
|
|
30
|
+
const key = km[1], rest = km[2].trim();
|
|
31
|
+
if (rest.startsWith('{')) {
|
|
32
|
+
result[key] = parseInlineObject(rest); i++;
|
|
33
|
+
} else if (rest === '') {
|
|
34
|
+
const nested = {}; i++;
|
|
35
|
+
while (i < lines.length && /^ /.test(lines[i])) {
|
|
36
|
+
const nl = lines[i].trim();
|
|
37
|
+
const nm = nl.match(/^(\w[\w-]*):\s*(.*)/);
|
|
38
|
+
if (nm) nested[nm[1]] = nm[2].trim().startsWith('{')
|
|
39
|
+
? parseInlineObject(nm[2].trim()) : parseScalar(nm[2].trim());
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
result[key] = nested;
|
|
43
|
+
} else { result[key] = parseScalar(rest); i++; }
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseFrontMatter(text) {
|
|
49
|
+
const FM_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
50
|
+
const m = text.match(FM_RE);
|
|
51
|
+
if (!m) return { meta: {}, body: text };
|
|
52
|
+
return { meta: parseSimpleYaml(m[1]), body: text.slice(m[0].length) };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function serializeFrontMatter(meta) {
|
|
56
|
+
const lines = ['---'];
|
|
57
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
58
|
+
if (typeof v === 'object' && v !== null) {
|
|
59
|
+
lines.push(`${k}:`);
|
|
60
|
+
for (const [sk, sv] of Object.entries(v)) {
|
|
61
|
+
if (typeof sv === 'object' && sv !== null) {
|
|
62
|
+
const inner = Object.entries(sv).map(([a,b]) => `${a}: ${JSON.stringify(b)}`).join(', ');
|
|
63
|
+
lines.push(` ${sk}: { ${inner} }`);
|
|
64
|
+
} else { lines.push(` ${sk}: ${JSON.stringify(sv)}`); }
|
|
65
|
+
}
|
|
66
|
+
} else { lines.push(`${k}: ${JSON.stringify(v)}`); }
|
|
67
|
+
}
|
|
68
|
+
lines.push('---');
|
|
69
|
+
return lines.join('\n');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.parseScalar = parseScalar;
|
|
73
|
+
exports.parseInlineObject = parseInlineObject;
|
|
74
|
+
exports.parseSimpleYaml = parseSimpleYaml;
|
|
75
|
+
exports.parseFrontMatter = parseFrontMatter;
|
|
76
|
+
exports.serializeFrontMatter = serializeFrontMatter;
|
|
77
|
+
|
|
78
|
+
})(typeof module !== 'undefined' && module.exports ? module.exports : (window.SDocYaml = {}));
|
package/server.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const PORT = process.env.PORT || 3000;
|
|
6
|
+
|
|
7
|
+
const MIME = {
|
|
8
|
+
'.html': 'text/html; charset=utf-8',
|
|
9
|
+
'.css': 'text/css',
|
|
10
|
+
'.js': 'application/javascript',
|
|
11
|
+
'.json': 'application/json',
|
|
12
|
+
'.md': 'text/plain',
|
|
13
|
+
'.smd': 'text/plain',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function serveFile(res, filePath) {
|
|
17
|
+
fs.readFile(filePath, (err, data) => {
|
|
18
|
+
if (err) {
|
|
19
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
20
|
+
res.end('Not Found');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const ext = path.extname(filePath);
|
|
24
|
+
res.writeHead(200, { 'Content-Type': MIME[ext] || 'application/octet-stream' });
|
|
25
|
+
res.end(data);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const server = http.createServer((req, res) => {
|
|
30
|
+
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
31
|
+
const pathname = url.pathname;
|
|
32
|
+
|
|
33
|
+
if (req.method !== 'GET') {
|
|
34
|
+
res.writeHead(405, { 'Content-Type': 'text/plain' });
|
|
35
|
+
res.end('Method Not Allowed');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (pathname === '/' || pathname === '/new') {
|
|
40
|
+
serveFile(res, path.join(__dirname, 'public', 'index.html'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (pathname.startsWith('/public/')) {
|
|
45
|
+
const filePath = path.join(__dirname, pathname);
|
|
46
|
+
// Prevent path traversal
|
|
47
|
+
const safe = path.resolve(filePath).startsWith(path.resolve(__dirname));
|
|
48
|
+
if (!safe) {
|
|
49
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
50
|
+
res.end('Forbidden');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
serveFile(res, filePath);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
58
|
+
res.end('Not Found');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
server.listen(PORT, () => {
|
|
62
|
+
console.log(`sdocs-dev running at http://localhost:${PORT}`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
module.exports = server;
|