@mostajs/orm-cli 0.6.4 → 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 +205 -2
- package/bin/validate.mjs +98 -0
- package/llms.txt +75 -0
- package/package.json +6 -4
package/bin/mostajs.sh
CHANGED
|
@@ -548,6 +548,10 @@ menu_main() {
|
|
|
548
548
|
echo -e " ${CYAN}r${RESET}) ${BOLD}Replicator${RESET} — CQRS master/slave, CDC rules, failover"
|
|
549
549
|
echo -e " ${GREEN}b${RESET}) ${BOLD}Bootstrap${RESET} — one-shot migration of a Prisma project"
|
|
550
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)"
|
|
551
555
|
echo -e " ${CYAN}0${RESET}) About / Help"
|
|
552
556
|
echo
|
|
553
557
|
echo -e " ${RED}q${RESET}) Quit"
|
|
@@ -569,6 +573,10 @@ menu_main() {
|
|
|
569
573
|
r|R) menu_replicator ;;
|
|
570
574
|
b|B) menu_bootstrap ;;
|
|
571
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 ;;
|
|
572
580
|
0) action_about ;;
|
|
573
581
|
q|Q) exit 0 ;;
|
|
574
582
|
*) warn "Unknown choice"; pause ;;
|
|
@@ -602,6 +610,139 @@ menu_install_bridge() {
|
|
|
602
610
|
pause
|
|
603
611
|
}
|
|
604
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
|
+
|
|
605
746
|
# ------------------------------------------------------------
|
|
606
747
|
# Interactive wrapper for `bootstrap` — one-shot full migration
|
|
607
748
|
# ------------------------------------------------------------
|
|
@@ -615,6 +756,7 @@ menu_bootstrap() {
|
|
|
615
756
|
echo " 2. Install ${CYAN}@mostajs/orm${RESET} + ${CYAN}@mostajs/orm-bridge${RESET} + ${CYAN}server-only${RESET}"
|
|
616
757
|
echo " 3. Convert ${CYAN}prisma/schema.prisma${RESET} → ${DIM}.mostajs/generated/entities.json${RESET}"
|
|
617
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})"
|
|
618
760
|
echo
|
|
619
761
|
warn "Existing code changes will be backed up but NOT committed — review the diff before pushing."
|
|
620
762
|
echo
|
|
@@ -3939,6 +4081,50 @@ run_subcommand() {
|
|
|
3939
4081
|
shift
|
|
3940
4082
|
node "$cli_dir/bin/install-bridge.mjs" "$@"
|
|
3941
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
|
+
;;
|
|
3942
4128
|
bootstrap|b)
|
|
3943
4129
|
# mostajs bootstrap : the full zero-touch migration for a Prisma project.
|
|
3944
4130
|
# 1. Rewrite every `new PrismaClient(...)` site (install-bridge --apply)
|
|
@@ -4358,8 +4544,16 @@ TREE
|
|
|
4358
4544
|
;;
|
|
4359
4545
|
esac
|
|
4360
4546
|
|
|
4361
|
-
# ─── Step
|
|
4362
|
-
|
|
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"
|
|
4363
4557
|
if (( BS_OK_CODEMOD && BS_OK_DEPS && BS_OK_CONVERT && BS_OK_DDL )); then
|
|
4364
4558
|
cat <<DONE
|
|
4365
4559
|
|
|
@@ -4408,6 +4602,15 @@ Usage :
|
|
|
4408
4602
|
$CLI_NAME install-bridge Codemod only (dry-run ; add --apply to write)
|
|
4409
4603
|
$CLI_NAME install-bridge --apply Rewrite PrismaClient sites to use @mostajs/orm-bridge
|
|
4410
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)
|
|
4411
4614
|
$CLI_NAME convert Run conversion (auto-detect schema type)
|
|
4412
4615
|
$CLI_NAME detect Print detected schemas
|
|
4413
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
|
+
}
|