@mostajs/orm-cli 0.6.3 → 0.7.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/CHANGELOG.md +474 -0
- package/bin/fix-mongo-id.mjs +259 -0
- package/bin/mongo-introspect.mjs +196 -0
- package/bin/mostajs.sh +209 -3
- package/bin/validate.mjs +98 -0
- package/llms.txt +75 -0
- package/package.json +6 -4
package/bin/mostajs.sh
CHANGED
|
@@ -246,10 +246,13 @@ detect_project() {
|
|
|
246
246
|
JSON_SCHEMAS=()
|
|
247
247
|
PKG_MANAGER=""
|
|
248
248
|
|
|
249
|
-
# Prisma
|
|
249
|
+
# Prisma (check prisma/ subdir first, then root)
|
|
250
250
|
if [[ -f "$PROJECT_ROOT/prisma/schema.prisma" ]]; then
|
|
251
251
|
PRISMA_SCHEMA="$PROJECT_ROOT/prisma/schema.prisma"
|
|
252
252
|
DETECTED_TYPES+=("prisma")
|
|
253
|
+
elif [[ -f "$PROJECT_ROOT/schema.prisma" ]]; then
|
|
254
|
+
PRISMA_SCHEMA="$PROJECT_ROOT/schema.prisma"
|
|
255
|
+
DETECTED_TYPES+=("prisma")
|
|
253
256
|
fi
|
|
254
257
|
|
|
255
258
|
# OpenAPI (common names)
|
|
@@ -545,6 +548,10 @@ menu_main() {
|
|
|
545
548
|
echo -e " ${CYAN}r${RESET}) ${BOLD}Replicator${RESET} — CQRS master/slave, CDC rules, failover"
|
|
546
549
|
echo -e " ${GREEN}b${RESET}) ${BOLD}Bootstrap${RESET} — one-shot migration of a Prisma project"
|
|
547
550
|
echo -e " ${GREEN}i${RESET}) ${BOLD}Install bridge${RESET} — codemod PrismaClient → bridge (dry-run / apply / restore)"
|
|
551
|
+
echo -e " ${GREEN}f${RESET}) ${BOLD}Fix Mongo _id${RESET} — codemod \`obj._id\` → \`obj.id\` after data-plug migration"
|
|
552
|
+
echo -e " ${GREEN}m${RESET}) ${BOLD}Mongo introspect${RESET} — live MongoDB → entities.json (reverse-engineer)"
|
|
553
|
+
echo -e " ${GREEN}v${RESET}) ${BOLD}Validate${RESET} — lint entities.json with the ORM validator (R001–R021)"
|
|
554
|
+
echo -e " ${GREEN}l${RESET}) ${BOLD}Load data${RESET} — .env-piloted cross-dialect load (Mongo/dump/JSON/SQL → DB)"
|
|
548
555
|
echo -e " ${CYAN}0${RESET}) About / Help"
|
|
549
556
|
echo
|
|
550
557
|
echo -e " ${RED}q${RESET}) Quit"
|
|
@@ -566,6 +573,10 @@ menu_main() {
|
|
|
566
573
|
r|R) menu_replicator ;;
|
|
567
574
|
b|B) menu_bootstrap ;;
|
|
568
575
|
i|I) menu_install_bridge ;;
|
|
576
|
+
f|F) menu_fix_ids ;;
|
|
577
|
+
m|M) menu_mongo_introspect ;;
|
|
578
|
+
v|V) menu_validate ;;
|
|
579
|
+
l|L) menu_load_data ;;
|
|
569
580
|
0) action_about ;;
|
|
570
581
|
q|Q) exit 0 ;;
|
|
571
582
|
*) warn "Unknown choice"; pause ;;
|
|
@@ -599,6 +610,139 @@ menu_install_bridge() {
|
|
|
599
610
|
pause
|
|
600
611
|
}
|
|
601
612
|
|
|
613
|
+
# ------------------------------------------------------------
|
|
614
|
+
# Interactive wrapper for `fix-ids` codemod (Mongo _id → id)
|
|
615
|
+
# ------------------------------------------------------------
|
|
616
|
+
menu_fix_ids() {
|
|
617
|
+
header
|
|
618
|
+
echo -e "${BOLD}${MAGENTA}▶ Fix Mongo _id → id — post data-plug migration codemod${RESET}"
|
|
619
|
+
echo
|
|
620
|
+
echo -e " ${DIM}@mostajs/orm normalizes ${CYAN}_id${DIM}→${CYAN}id${DIM} for every dialect (mongo included),${RESET}"
|
|
621
|
+
echo -e " ${DIM}so app code must read ${CYAN}obj.id${DIM}. This rewrites stale ${CYAN}obj._id${DIM} reads.${RESET}"
|
|
622
|
+
echo
|
|
623
|
+
echo -e " ${CYAN}1${RESET}) Dry-run : list \`._id\` reads that would be rewritten (default)"
|
|
624
|
+
echo -e " ${CYAN}2${RESET}) Apply : rewrite \`obj._id\` → \`obj.id\` (backups : *.mongoid.bak)"
|
|
625
|
+
echo -e " ${CYAN}3${RESET}) Restore : revert .mongoid.bak files (dry-run)"
|
|
626
|
+
echo -e " ${CYAN}4${RESET}) Restore : revert .mongoid.bak files (apply)"
|
|
627
|
+
echo -e " ${RED}0${RESET}) Back"
|
|
628
|
+
echo
|
|
629
|
+
local cli_dir
|
|
630
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
631
|
+
local choice; choice=$(ask "Choice" "1")
|
|
632
|
+
case "$choice" in
|
|
633
|
+
1) node "$cli_dir/bin/fix-mongo-id.mjs" --project "$PROJECT_ROOT" ;;
|
|
634
|
+
2) node "$cli_dir/bin/fix-mongo-id.mjs" --project "$PROJECT_ROOT" --apply ;;
|
|
635
|
+
3) node "$cli_dir/bin/fix-mongo-id.mjs" --project "$PROJECT_ROOT" --restore ;;
|
|
636
|
+
4) node "$cli_dir/bin/fix-mongo-id.mjs" --project "$PROJECT_ROOT" --restore --apply ;;
|
|
637
|
+
0) return ;;
|
|
638
|
+
*) warn "Unknown" ;;
|
|
639
|
+
esac
|
|
640
|
+
pause
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
# ------------------------------------------------------------
|
|
644
|
+
# Interactive wrapper for `mongo-introspect` (live MongoDB → entities.json)
|
|
645
|
+
# ------------------------------------------------------------
|
|
646
|
+
menu_mongo_introspect() {
|
|
647
|
+
load_env
|
|
648
|
+
header
|
|
649
|
+
echo -e "${BOLD}${MAGENTA}▶ Mongo introspect — reverse-engineer a live MongoDB${RESET}"
|
|
650
|
+
echo
|
|
651
|
+
echo -e " ${DIM}Samples documents per collection and infers EntitySchema[] →${RESET}"
|
|
652
|
+
echo -e " ${DIM}${GENERATED_DIR}/entities.json (the ORM drops _id/__v, ObjectId → string id).${RESET}"
|
|
653
|
+
echo
|
|
654
|
+
if [[ "${DB_DIALECT:-}" != "mongodb" ]]; then
|
|
655
|
+
warn "DB_DIALECT is '${DB_DIALECT:-<unset>}', not 'mongodb'."
|
|
656
|
+
info "Set it (menu 2 → i to import from the project .env), or enter a URI now."
|
|
657
|
+
fi
|
|
658
|
+
local uri; uri=$(ask "MongoDB URI" "${SGBD_URI:-mongodb://localhost:27017/mydb}")
|
|
659
|
+
[[ -z "$uri" ]] && { warn "No URI"; pause; return; }
|
|
660
|
+
local sample; sample=$(ask "Docs to sample per collection" "200")
|
|
661
|
+
local cli_dir
|
|
662
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
663
|
+
node "$cli_dir/bin/mongo-introspect.mjs" --uri "$uri" --sample "$sample" --out "$GENERATED_DIR/entities.json" --project "$PROJECT_ROOT"
|
|
664
|
+
pause
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
# ------------------------------------------------------------
|
|
668
|
+
# Interactive wrapper for `validate` (ORM validator over entities.json)
|
|
669
|
+
# ------------------------------------------------------------
|
|
670
|
+
menu_validate() {
|
|
671
|
+
header
|
|
672
|
+
echo -e "${BOLD}${MAGENTA}▶ Validate — ORMConceptValidator (R001–R021)${RESET}"
|
|
673
|
+
echo
|
|
674
|
+
if [[ ! -f "$GENERATED_DIR/entities.json" ]]; then
|
|
675
|
+
err "No entities.json. Run menu 1 (Convert) or menu m (Mongo introspect) first."
|
|
676
|
+
pause; return
|
|
677
|
+
fi
|
|
678
|
+
echo -e " ${CYAN}1${RESET}) Text report (default)"
|
|
679
|
+
echo -e " ${CYAN}2${RESET}) Markdown → report saved next to entities.json"
|
|
680
|
+
echo -e " ${CYAN}3${RESET}) JSON (stdout)"
|
|
681
|
+
echo -e " ${CYAN}4${RESET}) Text + cross-file rules (prompt for --src dir)"
|
|
682
|
+
echo -e " ${RED}0${RESET}) Back"
|
|
683
|
+
echo
|
|
684
|
+
local cli_dir
|
|
685
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
686
|
+
local choice; choice=$(ask "Choice" "1")
|
|
687
|
+
case "$choice" in
|
|
688
|
+
1) node "$cli_dir/bin/validate.mjs" --project "$PROJECT_ROOT" ;;
|
|
689
|
+
2) node "$cli_dir/bin/validate.mjs" --project "$PROJECT_ROOT" --format markdown --out "$GENERATED_DIR/validation-report.md" ;;
|
|
690
|
+
3) node "$cli_dir/bin/validate.mjs" --project "$PROJECT_ROOT" --format json ;;
|
|
691
|
+
4) local src; src=$(ask "Sources root (e.g. ./src)" "$PROJECT_ROOT/src")
|
|
692
|
+
node "$cli_dir/bin/validate.mjs" --project "$PROJECT_ROOT" --src "$src" ;;
|
|
693
|
+
0) return ;;
|
|
694
|
+
*) warn "Unknown" ;;
|
|
695
|
+
esac
|
|
696
|
+
pause
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
# ------------------------------------------------------------
|
|
700
|
+
# Interactive wrapper for `load-data` — .env-piloted cross-dialect load
|
|
701
|
+
# (delegates to @mostajs/orm-copy-data's `mostajs-load` bin)
|
|
702
|
+
# ------------------------------------------------------------
|
|
703
|
+
menu_load_data() {
|
|
704
|
+
load_env
|
|
705
|
+
header
|
|
706
|
+
echo -e "${BOLD}${MAGENTA}▶ Load data — charge un dump vers la base .env (cross-dialecte)${RESET}"
|
|
707
|
+
echo
|
|
708
|
+
echo -e " ${DIM}Destination (.env) : ${CYAN}${DB_DIALECT:-<DB_DIALECT non défini>}${DIM} → ${CYAN}${SGBD_URI:-<SGBD_URI non défini>}${RESET}"
|
|
709
|
+
if [[ -f "$GENERATED_DIR/entities.json" ]]; then
|
|
710
|
+
echo -e " ${DIM}Schémas : ${GENERATED_DIR}/entities.json ${GREEN}(présent)${RESET}"
|
|
711
|
+
else
|
|
712
|
+
warn "entities.json absent → lance d'abord le menu ${BOLD}m${RESET} (Mongo introspect) ou ${BOLD}1${RESET} (Convert)."
|
|
713
|
+
fi
|
|
714
|
+
echo
|
|
715
|
+
echo -e " ${BOLD}Source :${RESET}"
|
|
716
|
+
echo -e " ${CYAN}1${RESET}) MongoDB live (URI)"
|
|
717
|
+
echo -e " ${CYAN}2${RESET}) mongodump (dossier BSON → mongorestore)"
|
|
718
|
+
echo -e " ${CYAN}3${RESET}) Export JSON (fichier)"
|
|
719
|
+
echo -e " ${CYAN}4${RESET}) Dump SQL (fichier)"
|
|
720
|
+
echo -e " ${RED}0${RESET}) Retour"
|
|
721
|
+
echo
|
|
722
|
+
|
|
723
|
+
ensure_pkg "@mostajs/orm-copy-data" || { pause; return; }
|
|
724
|
+
local cd_main cd_bin
|
|
725
|
+
cd_main="$(resolve_pkg_path '@mostajs/orm-copy-data')" || { err "copy-data introuvable"; pause; return; }
|
|
726
|
+
cd_bin="$(dirname "$(dirname "$cd_main")")/bin/load-data.mjs"
|
|
727
|
+
[[ -f "$cd_bin" ]] || { err "bin mostajs-load absent — @mostajs/orm-copy-data ≥0.3.0 requis"; pause; return; }
|
|
728
|
+
|
|
729
|
+
local choice; choice=$(ask "Choix" "1")
|
|
730
|
+
case "$choice" in
|
|
731
|
+
1) local uri; uri=$(ask "URI Mongo source" "${SOURCE_SGBD_URI:-mongodb://127.0.0.1:27017/TicketFlow}")
|
|
732
|
+
node "$cd_bin" --project "$PROJECT_ROOT" --from mongo --source-uri "$uri" ;;
|
|
733
|
+
2) local dir; dir=$(ask "Dossier mongodump (BSON)" "./dump/TicketFlow")
|
|
734
|
+
local ruri; ruri=$(ask "URI Mongo de restauration" "${SOURCE_SGBD_URI:-mongodb://127.0.0.1:27017/tf_restore}")
|
|
735
|
+
node "$cd_bin" --project "$PROJECT_ROOT" --from mongodump --dump-dir "$dir" --restore-uri "$ruri" ;;
|
|
736
|
+
3) local f; f=$(ask "Fichier JSON" "./dump.json")
|
|
737
|
+
node "$cd_bin" --project "$PROJECT_ROOT" --from json --source-file "$f" ;;
|
|
738
|
+
4) local f; f=$(ask "Fichier SQL" "./dump.sql")
|
|
739
|
+
node "$cd_bin" --project "$PROJECT_ROOT" --from sql --source-file "$f" ;;
|
|
740
|
+
0) return ;;
|
|
741
|
+
*) warn "Inconnu" ;;
|
|
742
|
+
esac
|
|
743
|
+
pause
|
|
744
|
+
}
|
|
745
|
+
|
|
602
746
|
# ------------------------------------------------------------
|
|
603
747
|
# Interactive wrapper for `bootstrap` — one-shot full migration
|
|
604
748
|
# ------------------------------------------------------------
|
|
@@ -612,6 +756,7 @@ menu_bootstrap() {
|
|
|
612
756
|
echo " 2. Install ${CYAN}@mostajs/orm${RESET} + ${CYAN}@mostajs/orm-bridge${RESET} + ${CYAN}server-only${RESET}"
|
|
613
757
|
echo " 3. Convert ${CYAN}prisma/schema.prisma${RESET} → ${DIM}.mostajs/generated/entities.json${RESET}"
|
|
614
758
|
echo " 4. Write ${DIM}.mostajs/config.env${RESET} (default : sqlite ./data.sqlite) and init DDL"
|
|
759
|
+
echo " 5. Scan app code for Mongo residue ${CYAN}obj._id${RESET} / ${CYAN}new ObjectId()${RESET} (dry-run ; ${DIM}fix-ids${RESET})"
|
|
615
760
|
echo
|
|
616
761
|
warn "Existing code changes will be backed up but NOT committed — review the diff before pushing."
|
|
617
762
|
echo
|
|
@@ -3936,6 +4081,50 @@ run_subcommand() {
|
|
|
3936
4081
|
shift
|
|
3937
4082
|
node "$cli_dir/bin/install-bridge.mjs" "$@"
|
|
3938
4083
|
;;
|
|
4084
|
+
fix-ids|fix-mongo-id|fixids)
|
|
4085
|
+
# mostajs fix-ids [--apply] [--file X] [--project P] [--map old:new] [--restore]
|
|
4086
|
+
# Codemod : repairs Mongo-era `obj._id` reads left in app code after a
|
|
4087
|
+
# Mongoose → @mostajs/orm (data-plug) migration. The ORM's normalizer maps
|
|
4088
|
+
# `_id`→`id` for EVERY dialect (mongo included), so the app must read `.id`.
|
|
4089
|
+
# Dry-run by default ; pass --apply to write (backups : *.mongoid.bak).
|
|
4090
|
+
local cli_dir
|
|
4091
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
4092
|
+
shift
|
|
4093
|
+
node "$cli_dir/bin/fix-mongo-id.mjs" "$@"
|
|
4094
|
+
;;
|
|
4095
|
+
mongo-introspect|introspect|mi)
|
|
4096
|
+
# mostajs mongo-introspect [--uri ...] [--sample N] [--out F] [--project P]
|
|
4097
|
+
# Reverse-engineer a LIVE MongoDB into .mostajs/generated/entities.json by
|
|
4098
|
+
# sampling docs (uses $SGBD_URI if --uri is omitted). The "migrer" step for
|
|
4099
|
+
# Mongo projects that have no Prisma/OpenAPI schema.
|
|
4100
|
+
local cli_dir
|
|
4101
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
4102
|
+
shift
|
|
4103
|
+
node "$cli_dir/bin/mongo-introspect.mjs" "$@"
|
|
4104
|
+
;;
|
|
4105
|
+
validate|val)
|
|
4106
|
+
# mostajs validate [--entities F] [--src DIR] [--format text|json|markdown]
|
|
4107
|
+
# [--ignore r1,r2] [--out F] [--ci] [--max-warnings N]
|
|
4108
|
+
# Run @mostajs/orm's ORMConceptValidator (R001–R021) over entities.json.
|
|
4109
|
+
local cli_dir
|
|
4110
|
+
cli_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
4111
|
+
shift
|
|
4112
|
+
node "$cli_dir/bin/validate.mjs" "$@"
|
|
4113
|
+
;;
|
|
4114
|
+
load-data|load|ld)
|
|
4115
|
+
# mostajs load-data --from mongo|mongodump|json|sql [...flags]
|
|
4116
|
+
# Thin DELEGATE to @mostajs/orm-copy-data's `mostajs-load` bin (where the
|
|
4117
|
+
# feature lives). Destination from .env (DB_DIALECT/SGBD_URI) ; needs
|
|
4118
|
+
# entities.json (run `mostajs mongo-introspect` first).
|
|
4119
|
+
shift
|
|
4120
|
+
ensure_pkg "@mostajs/orm-copy-data" || exit 1
|
|
4121
|
+
local cd_main cd_bin
|
|
4122
|
+
cd_main="$(resolve_pkg_path '@mostajs/orm-copy-data')" \
|
|
4123
|
+
|| { err "@mostajs/orm-copy-data introuvable après installation."; exit 1; }
|
|
4124
|
+
cd_bin="$(dirname "$(dirname "$cd_main")")/bin/load-data.mjs"
|
|
4125
|
+
[[ -f "$cd_bin" ]] || { err "bin mostajs-load absent ($cd_bin) — mets à jour @mostajs/orm-copy-data (≥0.3.0)."; exit 1; }
|
|
4126
|
+
node "$cd_bin" --project "$PROJECT_ROOT" "$@"
|
|
4127
|
+
;;
|
|
3939
4128
|
bootstrap|b)
|
|
3940
4129
|
# mostajs bootstrap : the full zero-touch migration for a Prisma project.
|
|
3941
4130
|
# 1. Rewrite every `new PrismaClient(...)` site (install-bridge --apply)
|
|
@@ -4355,8 +4544,16 @@ TREE
|
|
|
4355
4544
|
;;
|
|
4356
4545
|
esac
|
|
4357
4546
|
|
|
4358
|
-
# ─── Step
|
|
4359
|
-
|
|
4547
|
+
# ─── Step : repair Mongo _id / ObjectId residue in app code ───
|
|
4548
|
+
# @mostajs/orm exposes ids as `id` (string) for EVERY dialect (mongo via its
|
|
4549
|
+
# normalizer), so app code must stop reading `obj._id` / wrapping `new ObjectId()`.
|
|
4550
|
+
# Run as a DRY-RUN here (non-destructive / CI-safe) and tell the user to apply.
|
|
4551
|
+
echo -e "\n\e[1m▶ Step 5/6 : repair Mongo _id / ObjectId in app code (codemod, dry-run)\e[0m"
|
|
4552
|
+
node "$cli_dir/bin/fix-mongo-id.mjs" --project "$PROJECT_ROOT" 2>&1 | sed 's/^/ /' || true
|
|
4553
|
+
info " To apply : ${CLI_NAME} fix-ids --apply (backups *.mongoid.bak ; undo: --restore --apply)"
|
|
4554
|
+
|
|
4555
|
+
# ─── Step 6 : Summary ───
|
|
4556
|
+
echo -e "\n\e[1m▶ Step 6/6 : Summary\e[0m"
|
|
4360
4557
|
if (( BS_OK_CODEMOD && BS_OK_DEPS && BS_OK_CONVERT && BS_OK_DDL )); then
|
|
4361
4558
|
cat <<DONE
|
|
4362
4559
|
|
|
@@ -4405,6 +4602,15 @@ Usage :
|
|
|
4405
4602
|
$CLI_NAME install-bridge Codemod only (dry-run ; add --apply to write)
|
|
4406
4603
|
$CLI_NAME install-bridge --apply Rewrite PrismaClient sites to use @mostajs/orm-bridge
|
|
4407
4604
|
$CLI_NAME install-bridge --restore --apply Undo a prior install-bridge
|
|
4605
|
+
$CLI_NAME fix-ids Codemod : Mongo \`obj._id\`→\`obj.id\` + \`new ObjectId(x)\`→\`x\`
|
|
4606
|
+
(dry-run ; add --apply to write, --restore to undo)
|
|
4607
|
+
$CLI_NAME mongo-introspect Reverse-engineer a live MongoDB → entities.json
|
|
4608
|
+
(--uri ... --sample N ; uses \$SGBD_URI by default)
|
|
4609
|
+
$CLI_NAME validate Lint entities.json with the ORM validator (R001–R021)
|
|
4610
|
+
(--format text|json|markdown --src DIR --ci)
|
|
4611
|
+
$CLI_NAME load-data --from mongo|mongodump|json|sql …
|
|
4612
|
+
.env-piloted cross-dialect load (delegates to
|
|
4613
|
+
@mostajs/orm-copy-data ; dest = DB_DIALECT/SGBD_URI)
|
|
4408
4614
|
$CLI_NAME convert Run conversion (auto-detect schema type)
|
|
4409
4615
|
$CLI_NAME detect Print detected schemas
|
|
4410
4616
|
$CLI_NAME health Run health checks
|
package/bin/validate.mjs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// validate.mjs — run @mostajs/orm's ORMConceptValidator over the entities the CLI
|
|
3
|
+
// generated (`.mostajs/generated/entities.json`). Thin wrapper around the
|
|
4
|
+
// published validator API (validateSchemas + reporters), so a migrated Mongo (or
|
|
5
|
+
// any) project can be linted for schema anti-patterns (R001–R021).
|
|
6
|
+
//
|
|
7
|
+
// @author Dr Hamid MADANI <drmdh@msn.com>
|
|
8
|
+
// License: AGPL-3.0-or-later
|
|
9
|
+
//
|
|
10
|
+
// Usage (invoked by bin/mostajs.sh as `mostajs validate`) :
|
|
11
|
+
//
|
|
12
|
+
// node validate.mjs # text report on entities.json
|
|
13
|
+
// node validate.mjs --entities path.json # explicit entities file
|
|
14
|
+
// node validate.mjs --src ./src # enable cross-file rules (R005…)
|
|
15
|
+
// node validate.mjs --format markdown --out report.md
|
|
16
|
+
// node validate.mjs --ignore R015,R017
|
|
17
|
+
// node validate.mjs --ci --max-warnings 0 # exit 1 if findings ≥ threshold
|
|
18
|
+
|
|
19
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { resolve } from 'node:path';
|
|
21
|
+
import { createRequire } from 'node:module';
|
|
22
|
+
import { pathToFileURL } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const argv = process.argv.slice(2);
|
|
26
|
+
const flag = (n) => argv.includes(`--${n}`);
|
|
27
|
+
const val = (n, d) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : d; };
|
|
28
|
+
|
|
29
|
+
const ROOT = resolve(val('project', process.cwd()));
|
|
30
|
+
const ENTITIES = resolve(val('entities', `${ROOT}/.mostajs/generated/entities.json`));
|
|
31
|
+
const SRC = val('src') ? resolve(val('src')) : undefined;
|
|
32
|
+
let FORMAT = val('format', 'text'); if (FORMAT === 'md') FORMAT = 'markdown';
|
|
33
|
+
const OUT = val('out') ? resolve(val('out')) : undefined;
|
|
34
|
+
const IGNORE = (val('ignore', '') || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
35
|
+
const CI = flag('ci');
|
|
36
|
+
const MAXW = Number(val('max-warnings', '0')) || 0;
|
|
37
|
+
|
|
38
|
+
const c = { red: s => `\x1b[31m${s}\x1b[0m`, yellow: s => `\x1b[33m${s}\x1b[0m`, green: s => `\x1b[32m${s}\x1b[0m`, cyan: s => `\x1b[36m${s}\x1b[0m`, bold: s => `\x1b[1m${s}\x1b[0m`, dim: s => `\x1b[2m${s}\x1b[0m` };
|
|
39
|
+
|
|
40
|
+
// ── Load entities.json (array of EntitySchema, as produced by convert / introspect) ──
|
|
41
|
+
let schemas;
|
|
42
|
+
try {
|
|
43
|
+
const raw = JSON.parse(readFileSync(ENTITIES, 'utf8'));
|
|
44
|
+
schemas = Array.isArray(raw) ? raw : (Array.isArray(raw.entities) ? raw.entities : null);
|
|
45
|
+
if (!schemas) throw new Error('not an EntitySchema[] (nor { entities: [...] })');
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.error(c.red(`✗ Cannot read entities : ${ENTITIES}`));
|
|
48
|
+
console.error(c.dim(` ${e.message}`));
|
|
49
|
+
console.error(` Generate it first : ${c.cyan('mostajs convert')} or ${c.cyan('mostajs mongo-introspect')}`);
|
|
50
|
+
process.exit(2);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Resolve the validator from the project first, then the CLI's own deps ──
|
|
54
|
+
let validator;
|
|
55
|
+
const cliDir = resolve(new URL('..', import.meta.url).pathname);
|
|
56
|
+
for (const base of [ROOT, cliDir]) {
|
|
57
|
+
try {
|
|
58
|
+
const p = require.resolve('@mostajs/orm/validator', { paths: [base] });
|
|
59
|
+
validator = await import(pathToFileURL(p).href);
|
|
60
|
+
break;
|
|
61
|
+
} catch { /* try next */ }
|
|
62
|
+
}
|
|
63
|
+
// Final fallback : bare specifier resolves against the CLI's own node_modules.
|
|
64
|
+
if (!validator) {
|
|
65
|
+
try { validator = await import('@mostajs/orm/validator'); } catch { /* give up below */ }
|
|
66
|
+
}
|
|
67
|
+
if (!validator) {
|
|
68
|
+
console.error(c.red('✗ @mostajs/orm (validator) not found in project or CLI.'));
|
|
69
|
+
console.error(` Install it : ${c.cyan('npm i @mostajs/orm')}`);
|
|
70
|
+
process.exit(2);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { validateSchemas, formatText, formatJson, formatMarkdown } = validator;
|
|
74
|
+
|
|
75
|
+
// ── Run ──
|
|
76
|
+
const report = await validateSchemas(schemas, { sourceRoot: SRC, ignore: IGNORE });
|
|
77
|
+
|
|
78
|
+
const rendered = FORMAT === 'json' ? formatJson(report, true)
|
|
79
|
+
: FORMAT === 'markdown' ? formatMarkdown(report)
|
|
80
|
+
: formatText(report, { verbose: flag('verbose') });
|
|
81
|
+
|
|
82
|
+
if (OUT) { writeFileSync(OUT, rendered); console.error(c.green(`✓ Report written : ${OUT}`)); }
|
|
83
|
+
else { console.log(rendered); }
|
|
84
|
+
|
|
85
|
+
// ── Summary line + CI gate ──
|
|
86
|
+
const sev = report.countBySeverity || {};
|
|
87
|
+
const warnOrWorse = (sev.error || 0) + (sev.warning || 0);
|
|
88
|
+
console.error(
|
|
89
|
+
`\n${c.bold('Validate')} : ${report.schemaCount} schema(s) · ` +
|
|
90
|
+
`${c.red((sev.error || 0) + ' error')} · ${c.yellow((sev.warning || 0) + ' warning')} · ` +
|
|
91
|
+
`${c.dim((sev.info || 0) + ' info')} ${c.dim(`(${report.durationMs}ms)`)}`,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (CI && warnOrWorse > MAXW) {
|
|
95
|
+
console.error(c.red(`✗ CI gate : ${warnOrWorse} finding(s) ≥ max-warnings (${MAXW})`));
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
process.exit(0);
|
package/llms.txt
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @mostajs/orm-cli — fiche LLM
|
|
2
|
+
> CLI universelle pour intégrer @mostajs/orm — `mostajs bootstrap` migre un projet Prisma vers 13 bases sans toucher au code.
|
|
3
|
+
|
|
4
|
+
- Version: 0.6.4 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
|
|
5
|
+
- Chemin: mostajs/mosta-orm-cli · Statut audit: partiel (paquet bin/ uniquement, pas de dist/ TS exporté)
|
|
6
|
+
|
|
7
|
+
## RÔLE
|
|
8
|
+
Outil en ligne de commande. La commande phare `mostajs bootstrap` migre un projet Prisma
|
|
9
|
+
existant vers @mostajs/orm en une passe : codemod (réécriture des `new PrismaClient(...)`),
|
|
10
|
+
installation des runtimes, conversion du schéma, application du DDL. Aucun changement de code
|
|
11
|
+
applicatif n'est requis. Fournit aussi un menu interactif et des sous-commandes utilitaires.
|
|
12
|
+
Ce paquet est un exécutable (bin), pas une bibliothèque importable.
|
|
13
|
+
|
|
14
|
+
## INSTALLATION
|
|
15
|
+
npx @mostajs/orm-cli bootstrap # zero-install (recommandé)
|
|
16
|
+
npm install -g @mostajs/orm-cli # global -> commande `mostajs`
|
|
17
|
+
|
|
18
|
+
## EXPORTS
|
|
19
|
+
Aucun export de bibliothèque. Le paquet expose un binaire :
|
|
20
|
+
- `mostajs` -> ./bin/mostajs-launcher.cjs
|
|
21
|
+
Fichiers bin : mostajs-launcher.cjs, install-bridge.mjs, mostajs.sh, mostajs.bat.
|
|
22
|
+
|
|
23
|
+
## API — SOUS-COMMANDES
|
|
24
|
+
- `mostajs bootstrap` — migration complète : codemod + install + convert + DDL
|
|
25
|
+
(chaque étape s'arrête à la première erreur, v0.4.1+)
|
|
26
|
+
- `mostajs install-bridge` — lance le codemod en dry-run (rapport, aucune écriture)
|
|
27
|
+
- `mostajs install-bridge --apply` — applique les changements du codemod
|
|
28
|
+
- `mostajs install-bridge --file <path>` — restreint le codemod à un fichier
|
|
29
|
+
- `mostajs install-bridge --restore --apply` — restaure les sauvegardes `*.prisma.bak`
|
|
30
|
+
- `mostajs convert` — auto-détecte le schéma (Prisma / OpenAPI / JSONSchema) et le convertit
|
|
31
|
+
- `mostajs detect` — affiche ce qui est détecté dans le projet
|
|
32
|
+
- `mostajs health` — vérifie Node / pnpm / schémas / état de entities.json
|
|
33
|
+
- `mostajs hash <password> [cost]` — hash bcrypt d'un mot de passe (données de seed)
|
|
34
|
+
- `mostajs verify <password> <hash>` — vérifie une paire mot de passe / hash
|
|
35
|
+
- `mostajs diagnose [email] [password]` — diagnostic de login
|
|
36
|
+
- `mostajs help` / `mostajs version`
|
|
37
|
+
- `mostajs` (sans argument) — menu interactif (convert, config URIs, init dialectes,
|
|
38
|
+
tests, services, métriques, logs, health, génération boilerplate, seeding, bootstrap)
|
|
39
|
+
|
|
40
|
+
## TYPES CLÉS
|
|
41
|
+
Sans objet — paquet purement CLI.
|
|
42
|
+
|
|
43
|
+
## PATTERN
|
|
44
|
+
```bash
|
|
45
|
+
cd my-existing-prisma-app
|
|
46
|
+
npx @mostajs/orm-cli bootstrap
|
|
47
|
+
npm run dev
|
|
48
|
+
# db.User.findMany(...) tourne maintenant sur l'un des 13 SGBD. Zéro changement de code.
|
|
49
|
+
|
|
50
|
+
# pour annuler :
|
|
51
|
+
npx @mostajs/orm-cli install-bridge --restore --apply
|
|
52
|
+
```
|
|
53
|
+
Le codemod réécrit chaque site `new PrismaClient(...)` en `createPrismaLikeDb()` importé
|
|
54
|
+
de `@mostajs/orm-bridge/prisma-client`, sauvegarde l'original en `<fichier>.prisma.bak`,
|
|
55
|
+
et préserve la forme d'export (`const db`, `const prisma`, `export default`…).
|
|
56
|
+
Le bootstrap produit `.mostajs/config.env`, `.mostajs/generated/entities.json`,
|
|
57
|
+
`.mostajs/seeds/*.json` et `.mostajs/logs/`.
|
|
58
|
+
|
|
59
|
+
## DÉPEND DE
|
|
60
|
+
- @mostajs/orm (dependency directe). À l'exécution, installe aussi dans le projet cible
|
|
61
|
+
@mostajs/orm-bridge et @mostajs/orm-adapter.
|
|
62
|
+
- bcryptjs (hash/verify), better-sqlite3 (DDL SQLite par défaut)
|
|
63
|
+
|
|
64
|
+
## PIÈGES
|
|
65
|
+
- `install-bridge` est dry-run PAR DÉFAUT — il faut `--apply` pour écrire les fichiers.
|
|
66
|
+
- Détection codemod : fichier devant contenir `import ... from '@prisma/client'` ET
|
|
67
|
+
`new PrismaClient(`. Les fichiers déjà migrés vers `@mostajs/orm-bridge/prisma-client`
|
|
68
|
+
sont ignorés (ré-exécution idempotente).
|
|
69
|
+
- Conversion de schéma : passe par @mostajs/orm-adapter (Prisma / OpenAPI / JSON Schema).
|
|
70
|
+
- Le bootstrap configure SQLite par défaut ; changer ensuite `DB_DIALECT` + `SGBD_URI`
|
|
71
|
+
dans `.mostajs/config.env` (ou `.env`) pour cibler un autre des 13 SGBD.
|
|
72
|
+
- Paquet non importable — ne pas tenter `import ... from '@mostajs/orm-cli'`.
|
|
73
|
+
|
|
74
|
+
## RÉFÉRENCES
|
|
75
|
+
- README.md · CHANGELOG.md · docs/How2.md, docs/MONITORING.md · install.sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/orm-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Universal CLI to integrate @mostajs/orm into any project — one-shot `mostajs bootstrap` migrates a Prisma project (codemod + deps + schema convert + DDL) to 13 databases with zero code change.",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|
|
13
13
|
"LICENSE",
|
|
14
|
-
"README.md"
|
|
14
|
+
"README.md",
|
|
15
|
+
"llms.txt",
|
|
16
|
+
"CHANGELOG.md"
|
|
15
17
|
],
|
|
16
18
|
"keywords": [
|
|
17
19
|
"mostajs",
|
|
@@ -42,8 +44,8 @@
|
|
|
42
44
|
"win32"
|
|
43
45
|
],
|
|
44
46
|
"dependencies": {
|
|
45
|
-
"@mostajs/orm": "^
|
|
47
|
+
"@mostajs/orm": "^2.6.0",
|
|
46
48
|
"bcryptjs": "^2.4.3",
|
|
47
49
|
"better-sqlite3": "^12.9.0"
|
|
48
50
|
}
|
|
49
|
-
}
|
|
51
|
+
}
|