@inovus-medical/docs 0.2.0 → 0.4.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/assets/styles.css CHANGED
@@ -102,8 +102,7 @@ a:hover { text-decoration: underline; }
102
102
  .layout {
103
103
  display: grid;
104
104
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--toc-w);
105
- max-width: 1400px;
106
- margin: 0 auto;
105
+ width: 100%;
107
106
  }
108
107
  .sidebar {
109
108
  position: sticky; top: var(--header-h); align-self: start;
package/bin/cli.js CHANGED
@@ -58,16 +58,18 @@ async function run() {
58
58
  if (cmd === 'dev') {
59
59
  const { pageCount, outPath, contentDir } = await build({ root, inDir, outDir })
60
60
  console.log(`✓ Built ${pageCount} page(s) from ${contentDir === '.' ? 'repo root' : contentDir + '/'}`)
61
- serve({ dir: outPath, port })
62
- console.log(`→ Serving http://localhost:${port} (watching ${contentDir === '.' ? 'repo root' : contentDir + '/'} for changes)`)
61
+ const { port: actual } = await serve({ dir: outPath, port })
62
+ const busy = actual !== port ? ` (port ${port} was busy)` : ''
63
+ console.log(`→ Serving http://localhost:${actual}${busy} (watching ${contentDir === '.' ? 'repo root' : contentDir + '/'} for changes)`)
63
64
  watchAndRebuild({ root, inDir: contentDir, outDir })
64
65
  return
65
66
  }
66
67
 
67
68
  if (cmd === 'serve') {
68
69
  const outPath = path.join(root, outDir)
69
- serve({ dir: outPath, port })
70
- console.log(`→ Serving ${outDir}/ at http://localhost:${port}`)
70
+ const { port: actual } = await serve({ dir: outPath, port })
71
+ const busy = actual !== port ? ` (port ${port} was busy)` : ''
72
+ console.log(`→ Serving ${outDir}/ at http://localhost:${actual}${busy}`)
71
73
  return
72
74
  }
73
75
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inovus-medical/docs",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Turn a folder of markdown into a themed, Cloudflare-ready docs site.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/build.js CHANGED
@@ -117,7 +117,16 @@ export async function build({ root = process.cwd(), inDir, outDir = 'dist' } = {
117
117
  const routeSegments = isIndex ? dirSegments : rawSegments
118
118
  const route = toRoute(routeSegments)
119
119
 
120
- const { html, headings, text, title } = renderer.render(content)
120
+ let rendered
121
+ try {
122
+ rendered = renderer.render(content)
123
+ } catch (err) {
124
+ const rel = path.relative(contentRoot, file)
125
+ console.warn(`⚠ Could not fully render ${rel}: ${err.message} — falling back to plain text.`)
126
+ const escaped = content.replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]))
127
+ rendered = { html: `<pre>${escaped}</pre>`, headings: [], text: content.slice(0, 2000), title: null }
128
+ }
129
+ const { html, headings, text, title } = rendered
121
130
  const pageTitle = data.title || title || (isIndex ? titleCase(dirSegments[dirSegments.length - 1] || config.title) : titleCase(leaf))
122
131
 
123
132
  const page = {
package/src/markdown.js CHANGED
@@ -42,7 +42,19 @@ export async function createRenderer() {
42
42
  md.use(
43
43
  await Shiki({
44
44
  themes: { light: 'github-light', dark: 'github-dark' },
45
- defaultColor: false
45
+ defaultColor: false,
46
+ // Real repos use fence languages Shiki doesn't ship (env, console, ...).
47
+ // Map the common ones, and fall back to plain text instead of crashing the build.
48
+ fallbackLanguage: 'text',
49
+ langAlias: {
50
+ env: 'ini',
51
+ dotenv: 'ini',
52
+ conf: 'ini',
53
+ console: 'bash',
54
+ shell: 'bash',
55
+ cmd: 'bat',
56
+ vue: 'html'
57
+ }
46
58
  })
47
59
  )
48
60
 
package/src/serve.js CHANGED
@@ -40,24 +40,47 @@ async function resolveFile(dir, urlPath) {
40
40
  }
41
41
  }
42
42
 
43
- export function serve({ dir, port = 8788 }) {
44
- const server = http.createServer(async (req, res) => {
45
- const file = await resolveFile(dir, req.url || '/')
46
- if (file) {
47
- res.writeHead(200, { 'content-type': TYPES[path.extname(file)] || 'application/octet-stream' })
48
- createReadStream(file).pipe(res)
49
- return
50
- }
51
- const notFound = path.join(dir, '404.html')
52
- try {
53
- const body = await fs.readFile(notFound)
54
- res.writeHead(404, { 'content-type': 'text/html; charset=utf-8' })
55
- res.end(body)
56
- } catch {
57
- res.writeHead(404, { 'content-type': 'text/plain' })
58
- res.end('Not found')
59
- }
43
+ /**
44
+ * Start a static server for `dir`. If the requested port is busy, automatically tries the
45
+ * next ones (up to maxAttempts) instead of crashing. Resolves with the server and the
46
+ * actual port it bound to.
47
+ */
48
+ export function serve({ dir, port = 8788, maxAttempts = 25 }) {
49
+ return new Promise((resolve, reject) => {
50
+ const server = http.createServer(async (req, res) => {
51
+ try {
52
+ const file = await resolveFile(dir, req.url || '/')
53
+ if (file) {
54
+ res.writeHead(200, { 'content-type': TYPES[path.extname(file)] || 'application/octet-stream' })
55
+ createReadStream(file).pipe(res)
56
+ return
57
+ }
58
+ const notFound = path.join(dir, '404.html')
59
+ try {
60
+ const body = await fs.readFile(notFound)
61
+ res.writeHead(404, { 'content-type': 'text/html; charset=utf-8' })
62
+ res.end(body)
63
+ } catch {
64
+ res.writeHead(404, { 'content-type': 'text/plain' })
65
+ res.end('Not found')
66
+ }
67
+ } catch (err) {
68
+ // A single bad request should never take down the dev server.
69
+ res.writeHead(500, { 'content-type': 'text/plain' })
70
+ res.end('Internal error: ' + err.message)
71
+ }
72
+ })
73
+
74
+ let attempt = 0
75
+ server.on('error', (err) => {
76
+ if (err.code === 'EADDRINUSE' && attempt < maxAttempts) {
77
+ attempt++
78
+ server.listen(port + attempt)
79
+ } else {
80
+ reject(err)
81
+ }
82
+ })
83
+ server.once('listening', () => resolve({ server, port: server.address().port }))
84
+ server.listen(port)
60
85
  })
61
- server.listen(port)
62
- return server
63
86
  }