quickdbd-cli 0.4.2__py3-none-any.whl → 0.5.0__py3-none-any.whl

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.
quickdbd_cli/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.4.2"
1
+ __version__ = "0.5.0"
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><rect width="128" height="128" rx="28" fill="#2563eb"/><rect x="22" y="22" width="42" height="36" rx="9" fill="#fff"/><path d="M44 58v19a10 10 0 0 0 10 10h12" fill="none" stroke="#fff" stroke-width="8"/><rect x="64" y="70" width="42" height="33" rx="8" fill="#a8c1f7"/></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><rect width="128" height="128" rx="28" fill="#2b5797"/><rect x="22" y="22" width="42" height="36" rx="9" fill="#fff"/><path d="M44 58v19a10 10 0 0 0 10 10h12" fill="none" stroke="#fff" stroke-width="8"/><rect x="64" y="70" width="42" height="33" rx="8" fill="#a9bfdd"/></svg>
@@ -34,8 +34,8 @@
34
34
  --t-edge: #b8bcc2;
35
35
  --row-hl: #dbe6f6;
36
36
  --row-hover: #eef3fa;
37
- --lit: #4361ee;
38
- --lit-deep: #2a3fb8;
37
+ --lit: #2b5797;
38
+ --lit-deep: #1c3a66;
39
39
  }
40
40
  /* Dark theme. viewer.js sets data-theme from the toggle, or from prefers-color-scheme when it's on auto. */
41
41
  :root[data-theme="dark"] {
quickdbd_cli/cli.py CHANGED
@@ -32,11 +32,12 @@ def _open(args) -> Project:
32
32
  return Project.open([Path(p) for p in args.paths], Path(args.layout) if getattr(args, "layout", None) else None)
33
33
 
34
34
 
35
+ def _name(p: Path) -> str:
36
+ return p.stem if p.is_file() else (p.resolve().name or "diagram")
37
+
38
+
35
39
  def _title(project: Project) -> str:
36
- if len(project.inputs) == 1:
37
- p = project.inputs[0]
38
- return p.stem if p.is_file() else (p.resolve().name or "diagram")
39
- return "diagram"
40
+ return _name(project.inputs[0]) if len(project.inputs) == 1 else "diagram"
40
41
 
41
42
 
42
43
  def _github_annotation(d: Diagnostic, level: str) -> str:
@@ -76,7 +77,30 @@ def _symbols(schema: Schema) -> dict:
76
77
  return {"tables": tables, "rels": rels}
77
78
 
78
79
 
80
+ def _check_each(args) -> int:
81
+ """Check each PATH on its own, as ``build --site`` builds them; folders with no schema files are skipped."""
82
+ from .project import discover
83
+
84
+ if args.format == "json" or args.stdin_file:
85
+ print("error: --each can't be used with --format json or --stdin-file", file=sys.stderr)
86
+ return 2
87
+ code, checked = 0, 0
88
+ for p in args.paths:
89
+ if Path(p).is_dir() and not discover([Path(p)]):
90
+ print(f"Skipped {p}: no .txt or .dbml schema files", file=sys.stderr)
91
+ continue
92
+ print(f"{p}:")
93
+ code = max(code, cmd_check(argparse.Namespace(**{**vars(args), "paths": [p], "each": False})))
94
+ checked += 1
95
+ if not checked:
96
+ print("error: no schema files found in: " + ", ".join(args.paths), file=sys.stderr)
97
+ return 2
98
+ return code
99
+
100
+
79
101
  def cmd_check(args) -> int:
102
+ if args.each:
103
+ return _check_each(args)
80
104
  project = _open(args)
81
105
  overrides = None
82
106
  if args.stdin_file:
@@ -143,7 +167,52 @@ def _built_page(args) -> tuple[str, dict] | int:
143
167
  return render_page(model, pos, _title(project)), model
144
168
 
145
169
 
170
+ def _build_site(args) -> int:
171
+ """One page per PATH plus an index linking them, in the folder ``args.site``."""
172
+ from urllib.parse import quote
173
+
174
+ from .html import render_index
175
+ from .project import discover
176
+
177
+ if args.layout:
178
+ print("error: --layout can't be used with --site: each PATH uses its own layout file", file=sys.stderr)
179
+ return 2
180
+ pages, seen, failed = [], {}, 0
181
+ for p in map(Path, args.paths):
182
+ if p.is_dir() and not discover([p]):
183
+ print(f"Skipped {p}: no .txt or .dbml schema files", file=sys.stderr)
184
+ continue
185
+ name = _name(p)
186
+ if name.lower() in seen or name.lower() == "index":
187
+ other = seen.get(name.lower(), "the index page")
188
+ print(f"error: {p} and {other} would both be written to {name}.html", file=sys.stderr)
189
+ return 2
190
+ seen[name.lower()] = p
191
+ res = _built_page(argparse.Namespace(**{**vars(args), "paths": [str(p)]}))
192
+ if isinstance(res, int):
193
+ failed = max(failed, res)
194
+ continue
195
+ pages.append((name, *res))
196
+ if failed: # nothing is written, so a failed build never leaves a half-updated site
197
+ return failed
198
+ if not pages:
199
+ print("error: no schema files found in: " + ", ".join(args.paths), file=sys.stderr)
200
+ return 2
201
+ out = Path(args.site)
202
+ out.mkdir(parents=True, exist_ok=True)
203
+ index = []
204
+ for name, page, model in pages:
205
+ (out / f"{name}.html").write_text(page, encoding="utf-8")
206
+ index.append((name, quote(f"{name}.html"), len(model["tables"]), len(model["rels"])))
207
+ print(f"Wrote {out / f'{name}.html'} ({len(model['tables'])} tables, {len(model['rels'])} relationships)")
208
+ (out / "index.html").write_text(render_index(index), encoding="utf-8")
209
+ print(f"Wrote {out / 'index.html'} ({len(pages)} diagrams)")
210
+ return 0
211
+
212
+
146
213
  def cmd_build(args) -> int:
214
+ if args.site:
215
+ return _build_site(args)
147
216
  res = _built_page(args)
148
217
  if isinstance(res, int):
149
218
  return res
@@ -575,11 +644,20 @@ def build_parser() -> argparse.ArgumentParser:
575
644
  metavar="PATH",
576
645
  help="read this schema file's text from stdin instead of disk (an editor's unsaved buffer)",
577
646
  )
647
+ sp.add_argument(
648
+ "--each",
649
+ action="store_true",
650
+ help="check each PATH as its own schema, as build --site does (folders with no schema files are skipped)",
651
+ )
578
652
  sp.set_defaults(func=cmd_check)
579
653
 
580
654
  sp = sub.add_parser("build", help="write an interactive HTML diagram")
581
655
  paths(sp)
582
- sp.add_argument("-o", "--output", default="diagram.html")
656
+ out = sp.add_mutually_exclusive_group()
657
+ out.add_argument("-o", "--output", default="diagram.html")
658
+ out.add_argument(
659
+ "--site", metavar="DIR", help="one page per PATH (named after it) plus an index.html linking them, in DIR"
660
+ )
583
661
  selectors(sp)
584
662
  sp.add_argument(
585
663
  "--diff-base", metavar="GIT_REF", help="colour tables/columns changed since this git ref (e.g. origin/main)"
quickdbd_cli/html.py CHANGED
@@ -190,3 +190,28 @@ def render_page(
190
190
  f"<script>{_asset('viewer.js')}</script>"
191
191
  f"{scripts}</body></html>\n"
192
192
  )
193
+
194
+
195
+ INDEX_CSS = (
196
+ ":root{color-scheme:light dark;--fg:#1f2328;--muted:#656d76;--bg:#fff;--line:#d0d7de}"
197
+ "@media (prefers-color-scheme:dark){:root{--fg:#e6edf3;--muted:#8d96a0;--bg:#0d1117;--line:#30363d}}"
198
+ "body{margin:0;background:var(--bg);color:var(--fg);font:15px/1.5 system-ui,sans-serif}"
199
+ "main{max-width:640px;margin:0 auto;padding:32px 16px}h1{font-size:20px;margin:0 0 16px}"
200
+ "ul{list-style:none;margin:0;padding:0}li{border-top:1px solid var(--line);padding:10px 0}"
201
+ "a{color:inherit;font-weight:600}span{color:var(--muted);margin-left:8px}"
202
+ )
203
+
204
+
205
+ def render_index(pages: list[tuple[str, str, int, int]], title: str = "Diagrams") -> str:
206
+ """``qdbd build --site``'s index: a link per (name, href, tables, relationships)."""
207
+ items = "".join(
208
+ f'<li><a href="{_escape(href)}">{_escape(name)}</a><span>{t} tables, {r} relationships</span></li>'
209
+ for name, href, t, r in pages
210
+ )
211
+ return (
212
+ '<!doctype html>\n<html lang="en"><head><meta charset="utf-8">'
213
+ '<meta name="viewport" content="width=device-width, initial-scale=1">'
214
+ '<meta name="generator" content="qdbd">'
215
+ f"{favicon()}<title>{_escape(title)}</title><style>{INDEX_CSS}</style></head>"
216
+ f"<body><main><h1>{_escape(title)}</h1><ul>{items}</ul></main></body></html>\n"
217
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: quickdbd-cli
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Compile QuickDBD-syntax schema files into interactive HTML ER diagrams, with no table limit.
5
5
  Project-URL: Homepage, https://qdbd.dev/
6
6
  Project-URL: Documentation, https://qdbd.dev/guide/
@@ -193,7 +193,7 @@ jobs:
193
193
  permissions: { contents: read, pull-requests: write }
194
194
  steps:
195
195
  - uses: actions/checkout@v4
196
- - uses: MarkPhamm/quickdbd-cli@v0.4.2
196
+ - uses: MarkPhamm/quickdbd-cli@v0.5.0
197
197
  with:
198
198
  path: erd/ # schema file(s) or folder(s)
199
199
  output: site/index.html
@@ -1,13 +1,13 @@
1
- quickdbd_cli/__init__.py,sha256=6hfVa12Q-nXyUEXr6SyKpqPEDJW6vlRHyPxlA27PfTs,22
1
+ quickdbd_cli/__init__.py,sha256=LBK46heutvn3KmsCrKIYu8RQikbfnjZaj2xFrXaeCzQ,22
2
2
  quickdbd_cli/__main__.py,sha256=E6Gls0DNz8GQK2K-kOUIx8cYhgANW_CH54VKrfCfs14,52
3
3
  quickdbd_cli/agent.py,sha256=LEuReTkwWDlRLs-GfQQMpMosHDFWbin0EAXRo73j-dA,37202
4
- quickdbd_cli/cli.py,sha256=kphlsJHzp-agb01rlw4PD2_SnriOtr-yRZPuW3I5B_E,30634
4
+ quickdbd_cli/cli.py,sha256=zP9wnA_gcLZQ1bt3YCVt14V87fYmdgzsmDpi8E_0g3Y,33862
5
5
  quickdbd_cli/convert.py,sha256=1AYFm4YmEav_wZp7xCAcL7TsD3qC17Y1I5g6V_fyAU0,16682
6
6
  quickdbd_cli/dbml.py,sha256=tHJOtMm1PHx4-yqs6rncPqdDfbwPcW8F54j_kKlWkx0,59413
7
7
  quickdbd_cli/dbt.py,sha256=AMHzERmc8WfL1tBLX4bJdPVghIHrqrfx8nMDbZMrueY,23100
8
8
  quickdbd_cli/diff.py,sha256=UBiCE3dk_cN-xSRZFQoLiIIFh_FAVZUpLwsdtHG9eBo,9986
9
9
  quickdbd_cli/export.py,sha256=XbSvWqFmhQHPcBtPHPit1SmhJ6qXrPyGlHYt7FpIMyo,3539
10
- quickdbd_cli/html.py,sha256=eZSECAaP-vxC_qGXOy0T7cXT7WkJeL7RixYvzMCDCZQ,8309
10
+ quickdbd_cli/html.py,sha256=tcbxiUmKhKfpAb7Pke1AVSRPK5VWaw9znpOi_3mQkoQ,9634
11
11
  quickdbd_cli/jsrt.py,sha256=_sRkmUbgHDTwK272jeTNUwojfjUKAkv4UeD2E2u3H1A,3464
12
12
  quickdbd_cli/layout.py,sha256=2wrryJ-SSJbMlOdxmtCTzC2_zkTtvRVs-OuOBS1bGEQ,10856
13
13
  quickdbd_cli/mcp.py,sha256=ibUg1a50BBco-hZABdxTexGZi_gclFCdcBDalTvFar8,12350
@@ -28,16 +28,16 @@ quickdbd_cli/assets/editor.js,sha256=Gare_MeAOKlc2QZpTR9nD8Ty-U6JBY3HRWAeMnDkCsU
28
28
  quickdbd_cli/assets/elk-LICENSE.md,sha256=Y36B9KG2tAeVNcSZ_KBeI4z3YFwf9bdtYNfafOlnAMk,14443
29
29
  quickdbd_cli/assets/elk.bundled.js,sha256=EiLkT5U853Rq8jgB5yNwj45vQ2uLN3pqX8dVLzSjB7M,1609707
30
30
  quickdbd_cli/assets/font-metrics.json,sha256=sXSiElxQSK8md8IEePLwh16TTdAqKt9rV140pvMlVS8,8654
31
- quickdbd_cli/assets/icon.svg,sha256=0T_BOpEdFzxQHg6wJL2rrEyk55nkjascmp_3xBE9IA0,338
31
+ quickdbd_cli/assets/icon.svg,sha256=z1KKpKN3dJbESzbC1EDS3NYOj9aKQw1pJfzwXFPg_M0,338
32
32
  quickdbd_cli/assets/render.js,sha256=WzxX_sUgdz0O4GgiaupKl8J_LI4YCqF9PUxzRbwebwo,31891
33
- quickdbd_cli/assets/style.css,sha256=ttyGKLti1sU-NMp9CBTDgaznfeU14XjWquFJr9XGsaA,18877
33
+ quickdbd_cli/assets/style.css,sha256=mTkpexDcMilBtds2WRk6SYiCrIA1DpZLueKmm3pRQw0,18877
34
34
  quickdbd_cli/assets/syntax-reference.md,sha256=WERcsWjyrfeHQPgxQriWKBsqFJnmWTQ2oRZjKYAHhKc,5322
35
35
  quickdbd_cli/assets/viewer.js,sha256=3rKXI80TNv9jF1dJNQa3Gpy0042yTcGfTz_8qg4h5WU,49676
36
- quickdbd_cli-0.4.2.dist-info/METADATA,sha256=uC4ifoOto5S6EsvclQEyw-e_72Kt4A-jAb61_S05cq8,17704
37
- quickdbd_cli-0.4.2.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
38
- quickdbd_cli-0.4.2.dist-info/entry_points.txt,sha256=nRhiYYug-XOY95nWUmi4oanico3Zjkfqk2OHtIE6SQ0,47
39
- quickdbd_cli-0.4.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
40
- quickdbd_cli-0.4.2.dist-info/licenses/NOTICE,sha256=pyv3BfIYiGzKLU4w-GcBe7GXoXxHqZ97Mf6Zpx_3_i0,2067
41
- quickdbd_cli-0.4.2.dist-info/licenses/src/quickdbd_cli/assets/Inter-LICENSE.txt,sha256=JiSB6ERSGzJvXs0FPlm5jIstp4yO4b27boF0MF5Uk1o,4380
42
- quickdbd_cli-0.4.2.dist-info/licenses/src/quickdbd_cli/assets/elk-LICENSE.md,sha256=Y36B9KG2tAeVNcSZ_KBeI4z3YFwf9bdtYNfafOlnAMk,14443
43
- quickdbd_cli-0.4.2.dist-info/RECORD,,
36
+ quickdbd_cli-0.5.0.dist-info/METADATA,sha256=NjeLisXVxAEYPnC53QjQpJv0IUrwcJgiYHHjf1BNfiw,17704
37
+ quickdbd_cli-0.5.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
38
+ quickdbd_cli-0.5.0.dist-info/entry_points.txt,sha256=nRhiYYug-XOY95nWUmi4oanico3Zjkfqk2OHtIE6SQ0,47
39
+ quickdbd_cli-0.5.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
40
+ quickdbd_cli-0.5.0.dist-info/licenses/NOTICE,sha256=pyv3BfIYiGzKLU4w-GcBe7GXoXxHqZ97Mf6Zpx_3_i0,2067
41
+ quickdbd_cli-0.5.0.dist-info/licenses/src/quickdbd_cli/assets/Inter-LICENSE.txt,sha256=JiSB6ERSGzJvXs0FPlm5jIstp4yO4b27boF0MF5Uk1o,4380
42
+ quickdbd_cli-0.5.0.dist-info/licenses/src/quickdbd_cli/assets/elk-LICENSE.md,sha256=Y36B9KG2tAeVNcSZ_KBeI4z3YFwf9bdtYNfafOlnAMk,14443
43
+ quickdbd_cli-0.5.0.dist-info/RECORD,,