Release 0.2.0: object tree, refs/modules options, docs
Add query object (--clear), modules -n, composite refs labels, FillChecking/TypeSet parsing, VERSION/CHANGELOG and --version. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+163
-8
@@ -13,6 +13,8 @@
|
||||
python tools/index/query_1c.py show Document.ЗаказКлиента -b crm3-26
|
||||
python tools/index/query_1c.py modules \"РВС_Transfer\" -b ws-rhana
|
||||
python tools/index/query_1c.py refs Catalog.Партнеры -b source
|
||||
python tools/index/query_1c.py object ЗаказКлиента -b target
|
||||
python tools/index/query_1c.py object Партнер -b crm3-26 --clear
|
||||
python tools/index/query_1c.py module CommonModules/РВС_TransferAPIДокументы
|
||||
"""
|
||||
|
||||
@@ -39,6 +41,7 @@ from index1c.cli import ( # noqa: E402
|
||||
resolve_project_root,
|
||||
)
|
||||
from index1c.config import resolve_object_type # noqa: E402
|
||||
from index1c import read_version_file # noqa: E402
|
||||
from index1c.search import ( # noqa: E402
|
||||
find_refs_to,
|
||||
get_module,
|
||||
@@ -47,6 +50,11 @@ from index1c.search import ( # noqa: E402
|
||||
search_modules,
|
||||
search_objects,
|
||||
)
|
||||
from index1c.object_view import ( # noqa: E402
|
||||
find_structure_matches,
|
||||
format_object_tree,
|
||||
load_object_structure,
|
||||
)
|
||||
|
||||
|
||||
def _open_or_exit(root: Path):
|
||||
@@ -95,14 +103,31 @@ def cmd_modules(args: argparse.Namespace) -> int:
|
||||
baseconfs = get_baseconfs_for_query(args, conn, root)
|
||||
except BaseconfError as e:
|
||||
return handle_baseconf_error(e)
|
||||
rows = search_modules(conn, args.query, configs=baseconfs, limit=args.limit)
|
||||
names_only = bool(args.names_only)
|
||||
rows = search_modules(
|
||||
conn,
|
||||
args.query,
|
||||
configs=baseconfs,
|
||||
limit=args.limit,
|
||||
names_only=names_only,
|
||||
)
|
||||
if not rows:
|
||||
print(format_not_found_modules(args.query, baseconfs=baseconfs, conn=conn))
|
||||
return 2
|
||||
for r in rows:
|
||||
print(f"- [{r['config']}] `{r['rel_path']}` ({r['module_kind']}, owner={r['owner']})")
|
||||
if r.get("snip"):
|
||||
print(f" {r['snip']}")
|
||||
syn = r.get("owner_synonym") or ""
|
||||
if names_only:
|
||||
# только имя модуля (owner) и синоним объекта-владельца
|
||||
syn_s = f" — {syn}" if syn else ""
|
||||
print(f"- [{r['config']}] `{r['owner']}`{syn_s}")
|
||||
else:
|
||||
syn_s = f", {syn}" if syn else ""
|
||||
print(
|
||||
f"- [{r['config']}] `{r['rel_path']}` "
|
||||
f"({r['module_kind']}, owner={r['owner']}{syn_s})"
|
||||
)
|
||||
if r.get("snip"):
|
||||
print(f" {r['snip']}")
|
||||
return 0
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -116,15 +141,41 @@ def cmd_refs(args: argparse.Namespace) -> int:
|
||||
baseconfs = get_baseconfs_for_query(args, conn, root)
|
||||
except BaseconfError as e:
|
||||
return handle_baseconf_error(e)
|
||||
rows = find_refs_to(conn, args.target, configs=baseconfs, limit=args.limit)
|
||||
rows, totals = find_refs_to(
|
||||
conn, args.target, configs=baseconfs, limit=args.limit
|
||||
)
|
||||
if not rows:
|
||||
scope = f" в {', '.join(baseconfs)}" if baseconfs else ""
|
||||
print(f"Ссылок на «{args.target}» не найдено{scope}.")
|
||||
return 2
|
||||
|
||||
current_cfg = None
|
||||
for r in rows:
|
||||
if r["config"] != current_cfg:
|
||||
current_cfg = r["config"]
|
||||
total = totals.get(current_cfg, 0)
|
||||
shown = sum(1 for x in rows if x["config"] == current_cfg)
|
||||
trunc = f", показано {shown}" if shown < total else ""
|
||||
print(f"## [{current_cfg}] — всего ссылок: {total}{trunc}")
|
||||
arrow = f"{r['to_kind']}.{r['to_name']}"
|
||||
if r.get("is_composite"):
|
||||
others = r.get("other_types") or []
|
||||
if others and len(others) <= 4:
|
||||
arrow += f" (среди прочего: {', '.join(others)})"
|
||||
elif others:
|
||||
arrow += f" (среди прочего: {', '.join(others[:3])}, … ещё {len(others) - 3})"
|
||||
else:
|
||||
arrow += " (среди прочего)"
|
||||
print(f"- `{r['from_full_name']}.{r['from_field']}` → {arrow}")
|
||||
|
||||
if len(totals) > 1:
|
||||
grand = sum(totals.values())
|
||||
shown = len(rows)
|
||||
print()
|
||||
print(
|
||||
f"- [{r['config']}] `{r['from_full_name']}.{r['from_field']}` "
|
||||
f"→ {r['to_kind']}.{r['to_name']}"
|
||||
f"Итого: {grand} ссылок в {len(totals)} конфигурациях; "
|
||||
f"выведено {shown} (лимит {args.limit} на каждую). "
|
||||
f"См. -b / --limit."
|
||||
)
|
||||
return 0
|
||||
finally:
|
||||
@@ -149,6 +200,76 @@ def cmd_show(args: argparse.Namespace) -> int:
|
||||
conn.close()
|
||||
|
||||
|
||||
def cmd_object(args: argparse.Namespace) -> int:
|
||||
root = resolve_project_root(args)
|
||||
conn = _open_or_exit(root)
|
||||
try:
|
||||
try:
|
||||
baseconfs = get_baseconfs_for_query(args, conn, root)
|
||||
except BaseconfError as e:
|
||||
return handle_baseconf_error(e)
|
||||
otype = resolve_object_type(args.type) if args.type else None
|
||||
matches = find_structure_matches(
|
||||
conn,
|
||||
args.query,
|
||||
configs=baseconfs,
|
||||
object_type=otype,
|
||||
limit=args.limit,
|
||||
)
|
||||
if not matches:
|
||||
print(format_not_found_object(args.query, baseconfs=baseconfs, conn=conn), file=sys.stderr)
|
||||
return 2
|
||||
|
||||
for i, m in enumerate(matches):
|
||||
if i:
|
||||
print()
|
||||
obj = load_object_structure(m)
|
||||
# подтянуть FillChecking/типы из свежего XML в matched_fields
|
||||
matched = list(m.get("matched_fields") or [])
|
||||
if matched and obj.get("fields"):
|
||||
by_f = {
|
||||
(
|
||||
f.get("tabular_section") or "",
|
||||
f.get("name") or "",
|
||||
f.get("kind") or "",
|
||||
): f
|
||||
for f in obj["fields"]
|
||||
}
|
||||
for mf in matched:
|
||||
key = (
|
||||
mf.get("tabular_section") or "",
|
||||
mf.get("name") or "",
|
||||
mf.get("kind") or "",
|
||||
)
|
||||
src = by_f.get(key)
|
||||
if src:
|
||||
mf["fill_checking"] = src.get("fill_checking") or ""
|
||||
mf["types"] = src.get("types") or mf.get("types")
|
||||
mf["synonym"] = src.get("synonym") or mf.get("synonym")
|
||||
mf["refs"] = src.get("refs") or mf.get("refs")
|
||||
# точное совпадение объекта (score 0) → clear без дерева;
|
||||
# иначе при найденных реквизитах — clear только по ним
|
||||
kind = m.get("match_kind") or "object"
|
||||
if args.clear and matched and m.get("score", 100) > 0:
|
||||
kind = "field"
|
||||
elif args.clear and m.get("score", 100) == 0:
|
||||
kind = "object"
|
||||
print(
|
||||
format_object_tree(
|
||||
obj,
|
||||
clear=bool(args.clear),
|
||||
matched_fields=matched,
|
||||
match_kind=kind,
|
||||
)
|
||||
)
|
||||
if len(matches) > 1:
|
||||
print()
|
||||
print(f"Найдено объектов: {len(matches)}. Уточните -b / --type / --limit.")
|
||||
return 0
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def cmd_module(args: argparse.Namespace) -> int:
|
||||
root = resolve_project_root(args)
|
||||
conn = _open_or_exit(root)
|
||||
@@ -177,6 +298,11 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
"Файл настроек утилиты — --config (-c): см. tools/index/config.example.json"
|
||||
),
|
||||
)
|
||||
p.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
version=f"%(prog)s {read_version_file()}",
|
||||
)
|
||||
add_tool_args(p)
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
@@ -191,12 +317,23 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
m.add_argument("query")
|
||||
add_baseconf_args(m)
|
||||
m.add_argument("--limit", type=int, default=30)
|
||||
m.add_argument(
|
||||
"--names-only",
|
||||
"-n",
|
||||
action="store_true",
|
||||
help="Только имена модулей (owner) и синонимы, без пути и фрагментов кода",
|
||||
)
|
||||
m.set_defaults(func=cmd_modules)
|
||||
|
||||
ref = sub.add_parser("refs", help="Обратный индекс: кто ссылается на объект")
|
||||
ref.add_argument("target", help="Catalog.Партнеры | CatalogRef.Партнеры | Партнеры")
|
||||
add_baseconf_args(ref)
|
||||
ref.add_argument("--limit", type=int, default=100)
|
||||
ref.add_argument(
|
||||
"--limit",
|
||||
type=int,
|
||||
default=100,
|
||||
help="Макс. строк на каждую конфигурацию 1С (по умолчанию 100)",
|
||||
)
|
||||
ref.set_defaults(func=cmd_refs)
|
||||
|
||||
sh = sub.add_parser("show", help="Карточка объекта (JSON: поля, типы, ссылки)")
|
||||
@@ -204,6 +341,24 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
add_baseconf_args(sh)
|
||||
sh.set_defaults(func=cmd_show)
|
||||
|
||||
ob = sub.add_parser(
|
||||
"object",
|
||||
help="Структура объекта: дерево реквизитов, обязательность, типы",
|
||||
)
|
||||
ob.add_argument("query", help="Имя/синоним объекта или реквизита")
|
||||
add_baseconf_args(ob)
|
||||
ob.add_argument("--type", help="Ограничить типом: Document, Catalog, …")
|
||||
ob.add_argument("--limit", type=int, default=10, help="Макс. число объектов")
|
||||
ob.add_argument(
|
||||
"--clear",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Краткий вывод: только найденные реквизиты; "
|
||||
"если совпал сам объект — только его имя без дерева"
|
||||
),
|
||||
)
|
||||
ob.set_defaults(func=cmd_object)
|
||||
|
||||
md = sub.add_parser("module", help="Метаданные модуля по пути или owner")
|
||||
md.add_argument("path", help="CommonModules/… или CommonModule.Имя")
|
||||
add_baseconf_args(md)
|
||||
|
||||
Reference in New Issue
Block a user