@memberjunction/metadata-sync 2.46.0 → 2.47.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/README.md +124 -13
- package/dist/commands/pull/index.d.ts +135 -0
- package/dist/commands/pull/index.js +187 -18
- package/dist/commands/pull/index.js.map +1 -1
- package/dist/commands/push/index.d.ts +1 -0
- package/dist/commands/push/index.js +75 -33
- package/dist/commands/push/index.js.map +1 -1
- package/dist/commands/status/index.js +35 -2
- package/dist/commands/status/index.js.map +1 -1
- package/dist/commands/watch/index.js +1 -1
- package/dist/commands/watch/index.js.map +1 -1
- package/dist/config.d.ts +141 -0
- package/dist/config.js +81 -0
- package/dist/config.js.map +1 -1
- package/dist/hooks/init.js +6 -1
- package/dist/hooks/init.js.map +1 -1
- package/dist/lib/provider-utils.d.ts +76 -4
- package/dist/lib/provider-utils.js +93 -28
- package/dist/lib/provider-utils.js.map +1 -1
- package/dist/lib/sync-engine.d.ts +239 -5
- package/dist/lib/sync-engine.js +314 -5
- package/dist/lib/sync-engine.js.map +1 -1
- package/oclif.manifest.json +8 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/pull/index.ts"],"names":[],"mappings":";;;;;AAAA,sCAA6C;AAC7C,wDAA0B;AAC1B,gDAAwB;AACxB,+CAA2C;AAC3C,8DAA8B;AAC9B,yCAAmF;AACnF,uDAA+D;AAC/D,+CAA+C;AAC/C,6DAA8F;AAE9F,MAAqB,IAAK,SAAQ,cAAO;IACvC,MAAM,CAAC,WAAW,GAAG,4CAA4C,CAAC;IAElE,MAAM,CAAC,QAAQ,GAAG;QAChB,2DAA2D;QAC3D,uGAAuG;KACxG,CAAC;IAEF,MAAM,CAAC,KAAK,GAAG;QACb,MAAM,EAAE,YAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qBAAqB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC5E,MAAM,EAAE,YAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC;QACvF,SAAS,EAAE,YAAK,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC;KAChG,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAA,qBAAG,GAAE,CAAC;QAEtB,IAAI,CAAC;YACH,iBAAiB;YACjB,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAA,qBAAY,GAAE,CAAC;YAChC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,IAAI,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;YAClF,CAAC;YAED,2BAA2B;YAC3B,MAAM,QAAQ,GAAG,MAAM,IAAA,mCAAkB,EAAC,QAAQ,CAAC,CAAC;YAEpD,yBAAyB;YACzB,MAAM,UAAU,GAAG,IAAI,wBAAU,CAAC,IAAA,8BAAa,GAAE,CAAC,CAAC;YACnD,MAAM,UAAU,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;YAExC,wBAAwB;YACxB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAElE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,MAAM,8BAA8B,CAAC,CAAC;YAC3F,CAAC;YAED,IAAI,SAAiB,CAAC;YACtB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,uCAAuC;gBACvC,SAAS,GAAG,MAAM,IAAA,gBAAM,EAAC;oBACvB,OAAO,EAAE,0CAA0C,KAAK,CAAC,MAAM,sBAAsB;oBACrF,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;iBAC5D,CAAC,CAAC;YACL,CAAC;YAED,MAAM,YAAY,GAAG,MAAM,IAAA,yBAAgB,EAAC,SAAS,CAAC,CAAC;YACvD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,IAAI,CAAC,KAAK,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAC;YAC7D,CAAC;YAED,eAAe;YACf,OAAO,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC;YACjD,MAAM,EAAE,GAAG,IAAI,cAAO,EAAE,CAAC;YAEzB,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjB,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YACxB,CAAC;iBAAM,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBACrC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC;YACpC,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;gBAC9B,UAAU,EAAE,KAAK,CAAC,MAAM;gBACxB,WAAW,EAAE,MAAM;aACpB,EAAE,IAAA,8BAAa,GAAE,CAAC,CAAC;YAEpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,CAAC,KAAK,CAAC,2BAA2B,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;YAC/D,CAAC;YAED,OAAO,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;YAE1D,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,OAAO,CAAC,MAAM,eAAe,SAAS,EAAE,CAAC,CAAC;gBACzF,OAAO;YACT,CAAC;YAED,sBAAsB;YACtB,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,qCAAqC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACpC,IAAI,SAAS,GAAG,CAAC,CAAC;YAElB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,UAAU,GAAwB,EAAE,CAAC;oBAC3C,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;wBACxC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;oBACxC,CAAC;oBAED,iBAAiB;oBACjB,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;oBAClF,SAAS,EAAE,CAAC;oBAEZ,OAAO,CAAC,IAAI,GAAG,uBAAuB,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAC9E,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,IAAI,CAAC,6BAA8B,KAAa,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;YAED,OAAO,CAAC,OAAO,CAAC,UAAU,SAAS,eAAe,SAAS,EAAE,CAAC,CAAC;QAEjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,KAAc,CAAC,CAAC;QAC7B,CAAC;gBAAS,CAAC;YACT,+BAA+B;YAC/B,MAAM,IAAA,gCAAe,GAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAAC,UAAkB;QACpD,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,qDAAqD;QACrD,MAAM,UAAU,GAAG,KAAK,EAAE,GAAW,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC5C,MAAM,MAAM,GAAG,MAAM,IAAA,yBAAgB,EAAC,QAAQ,CAAC,CAAC;oBAEhD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACtB,CAAC;yBAAM,CAAC;wBACN,UAAU;wBACV,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,MAAW,EACX,UAA+B,EAC/B,SAAiB,EACjB,YAAiB,EACjB,UAAsB;QAEtB,oBAAoB;QACpB,MAAM,UAAU,GAAe;YAC7B,UAAU,EAAE,UAAU;YACtB,MAAM,EAAE,EAAE;YACV,IAAI,EAAE;gBACJ,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACtC,QAAQ,EAAE,EAAE;aACb;SACF,CAAC;QAEF,iBAAiB;QACjB,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7D,0BAA0B;YAC1B,IAAI,UAAU,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;gBACxC,SAAS;YACX,CAAC;YAED,uBAAuB;YACvB,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,SAAS;YACX,CAAC;YAED,0CAA0C;YAC1C,IAAI,MAAM,IAAI,CAAC,sBAAsB,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC;gBAC3E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAC5C,SAAS,EACT,UAAU,EACV,SAAS,EACT,MAAM,CAAC,UAAU,CAAC,CACnB,CAAC;gBACF,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,SAAS,QAAQ,EAAE,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,UAAU,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,sCAAsC;QACtC,IAAI,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC;YACvC,UAAU,CAAC,eAAe,GAAG,MAAM,IAAI,CAAC,mBAAmB,CACzD,MAAM,EACN,YAAY,CAAC,IAAI,CAAC,eAAe,EACjC,UAAU,CACX,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,UAAU,CAAC,IAAK,CAAC,QAAQ,GAAG,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAE5E,sBAAsB;QACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,kBAAkB;QAClB,MAAM,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAClC,SAAiB,EACjB,UAAe,EACf,YAAiB;QAEjB,0DAA0D;QAC1D,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,yCAAyC;QACzC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa;YAC9C,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAEjE,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC;YACjF,mFAAmF;YACnF,OAAO,UAAU,CAAC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC9B,SAAiB,EACjB,UAA+B,EAC/B,SAAiB,EACjB,OAAe;QAEf,2DAA2D;QAC3D,IAAI,SAAS,GAAG,MAAM,CAAC;QAEvB,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;aAAM,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACxD,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/D,SAAS,GAAG,OAAO,CAAC;YACtB,CAAC;iBAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5D,SAAS,GAAG,SAAS,CAAC;YACxB,CAAC;QACH,CAAC;aAAM,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,SAAS,GAAG,MAAM,CAAC;QACrB,CAAC;aAAM,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACxG,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/E,MAAM,QAAQ,GAAG,GAAG,YAAY,IAAI,SAAS,CAAC,WAAW,EAAE,GAAG,SAAS,EAAE,CAAC;QAC1E,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,MAAM,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAE/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,aAAa,CAAC,UAA+B,EAAE,YAAiB;QACtE,2CAA2C;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEvC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACrD,iDAAiD;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,GAAG,CAAC,KAAK,CAAC,iEAAiE,CAAC,EAAE,CAAC;gBACjF,iCAAiC;gBACjC,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;YACvC,CAAC;YACD,oCAAoC;YACpC,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;gBACrB,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC;YACvD,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IACtF,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,YAAiB,EACjB,aAAkD,EAClD,UAAsB;QAEtB,MAAM,eAAe,GAAiC,EAAE,CAAC;QAEzD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC;gBACH,qCAAqC;gBACrC,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACvD,IAAI,CAAC,cAAc,EAAE,CAAC;oBACpB,SAAS,CAAC,oDAAoD;gBAChE,CAAC;gBAED,mCAAmC;gBACnC,IAAI,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;gBACtF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,MAAM,IAAI,SAAS,MAAM,CAAC,MAAM,GAAG,CAAC;gBACtC,CAAC;gBAED,uBAAuB;gBACvB,MAAM,EAAE,GAAG,IAAI,cAAO,EAAE,CAAC;gBACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;oBAC9B,UAAU,EAAE,MAAM,CAAC,MAAM;oBACzB,WAAW,EAAE,MAAM;iBACpB,EAAE,IAAA,8BAAa,GAAE,CAAC,CAAC;gBAEpB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,IAAI,CAAC,IAAI,CAAC,0BAA0B,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;oBAC7E,SAAS;gBACX,CAAC;gBAED,8BAA8B;gBAC9B,MAAM,cAAc,GAAiB,EAAE,CAAC;gBACxC,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBAC3C,MAAM,UAAU,GAAe;wBAC7B,MAAM,EAAE,EAAE;qBACX,CAAC;oBAEF,4EAA4E;oBAC5E,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;wBACpE,uBAAuB;wBACvB,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;4BAClC,SAAS;wBACX,CAAC;wBAED,2CAA2C;wBAC3C,IAAI,SAAS,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;4BACpC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;4BAC3E,IAAI,eAAe,EAAE,CAAC;gCACpB,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,WAAW,eAAe,EAAE,CAAC;4BAC9D,CAAC;4BACD,SAAS;wBACX,CAAC;wBAED,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,UAAU,CAAC;oBAC5C,CAAC;oBAED,6CAA6C;oBAC7C,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;wBAC3B,UAAU,CAAC,eAAe,GAAG,MAAM,IAAI,CAAC,mBAAmB,CACzD,aAAa,EACb,MAAM,CAAC,eAAe,EACtB,UAAU,CACX,CAAC;oBACJ,CAAC;oBAED,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAClC,CAAC;gBAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9B,eAAe,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC;gBACxC,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,yBAAyB,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC;IAEO,eAAe,CAAC,YAAiB,EAAE,KAAU;QACnD,qDAAqD;QACrD,+CAA+C;QAC/C,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACnE,IAAI,UAAU,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3D,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;;AAzXH,uBA0XC","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { select } from '@inquirer/prompts';\nimport ora from 'ora-classic';\nimport { loadMJConfig, loadEntityConfig, RelatedEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { RunView } from '@memberjunction/core';\nimport { getSystemUser, initializeProvider, cleanupProvider } from '../../lib/provider-utils';\n\nexport default class Pull extends Command {\n static description = 'Pull metadata from database to local files';\n \n static examples = [\n `<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\"`,\n `<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\" --filter=\"CategoryID='customer-service-id'\"`,\n ];\n \n static flags = {\n entity: Flags.string({ description: 'Entity name to pull', required: true }),\n filter: Flags.string({ description: 'Additional filter for pulling specific records' }),\n 'dry-run': Flags.boolean({ description: 'Show what would be pulled without actually pulling' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Pull);\n const spinner = ora();\n \n try {\n // Load MJ config\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n // Initialize data provider\n const provider = await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directory\n const entityDirs = await this.findEntityDirectories(flags.entity);\n \n if (entityDirs.length === 0) {\n this.error(`No directory found for entity \"${flags.entity}\". Run \"mj-sync init\" first.`);\n }\n \n let targetDir: string;\n if (entityDirs.length === 1) {\n targetDir = entityDirs[0];\n } else {\n // Multiple directories found, ask user\n targetDir = await select({\n message: `Multiple directories found for entity \"${flags.entity}\". Which one to use?`,\n choices: entityDirs.map(dir => ({ name: dir, value: dir }))\n });\n }\n \n const entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n this.error(`Invalid entity configuration in ${targetDir}`);\n }\n \n // Pull records\n spinner.start(`Pulling ${flags.entity} records`);\n const rv = new RunView();\n \n let filter = '';\n if (flags.filter) {\n filter = flags.filter;\n } else if (entityConfig.pull?.filter) {\n filter = entityConfig.pull.filter;\n }\n \n const result = await rv.RunView({\n EntityName: flags.entity,\n ExtraFilter: filter\n }, getSystemUser());\n \n if (!result.Success) {\n this.error(`Failed to pull records: ${result.ErrorMessage}`);\n }\n \n spinner.succeed(`Found ${result.Results.length} records`);\n \n if (flags['dry-run']) {\n this.log(`\\nDry run mode - would pull ${result.Results.length} records to ${targetDir}`);\n return;\n }\n \n // Process each record\n const entityInfo = syncEngine.getEntityInfo(flags.entity);\n if (!entityInfo) {\n this.error(`Entity information not found for: ${flags.entity}`);\n }\n \n spinner.start('Processing records');\n let processed = 0;\n \n for (const record of result.Results) {\n try {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = record[pk.Name];\n }\n \n // Process record\n await this.processRecord(record, primaryKey, targetDir, entityConfig, syncEngine);\n processed++;\n \n spinner.text = `Processing records (${processed}/${result.Results.length})`;\n } catch (error) {\n this.warn(`Failed to process record: ${(error as any).message || error}`);\n }\n }\n \n spinner.succeed(`Pulled ${processed} records to ${targetDir}`);\n \n } catch (error) {\n spinner.fail('Pull failed');\n this.error(error as Error);\n } finally {\n // Clean up database connection\n await cleanupProvider();\n }\n }\n \n private async findEntityDirectories(entityName: string): Promise<string[]> {\n const dirs: string[] = [];\n \n // Search for directories with matching entity config\n const searchDirs = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(dir, entry.name);\n const config = await loadEntityConfig(fullPath);\n \n if (config && config.entity === entityName) {\n dirs.push(fullPath);\n } else {\n // Recurse\n await searchDirs(fullPath);\n }\n }\n }\n };\n \n await searchDirs(process.cwd());\n return dirs;\n }\n \n private async processRecord(\n record: any, \n primaryKey: Record<string, any>,\n targetDir: string, \n entityConfig: any,\n syncEngine: SyncEngine\n ): Promise<void> {\n // Build record data\n const recordData: RecordData = {\n primaryKey: primaryKey,\n fields: {},\n sync: {\n lastModified: new Date().toISOString(),\n checksum: ''\n }\n };\n \n // Process fields\n for (const [fieldName, fieldValue] of Object.entries(record)) {\n // Skip primary key fields\n if (primaryKey[fieldName] !== undefined) {\n continue;\n }\n \n // Skip internal fields\n if (fieldName.startsWith('__mj_')) {\n continue;\n }\n \n // Check if this is an external file field\n if (await this.shouldExternalizeField(fieldName, fieldValue, entityConfig)) {\n const fileName = await this.createExternalFile(\n targetDir,\n primaryKey,\n fieldName,\n String(fieldValue)\n );\n recordData.fields[fieldName] = `@file:${fileName}`;\n } else {\n recordData.fields[fieldName] = fieldValue;\n }\n }\n \n // Pull related entities if configured\n if (entityConfig.pull?.relatedEntities) {\n recordData.relatedEntities = await this.pullRelatedEntities(\n record,\n entityConfig.pull.relatedEntities,\n syncEngine\n );\n }\n \n // Calculate checksum\n recordData.sync!.checksum = syncEngine.calculateChecksum(recordData.fields);\n \n // Determine file path\n const fileName = this.buildFileName(primaryKey, entityConfig);\n const filePath = path.join(targetDir, fileName);\n \n // Write JSON file\n await fs.writeJson(filePath, recordData, { spaces: 2 });\n }\n \n private async shouldExternalizeField(\n fieldName: string, \n fieldValue: any,\n entityConfig: any\n ): Promise<boolean> {\n // Only externalize string fields with significant content\n if (typeof fieldValue !== 'string') {\n return false;\n }\n \n // Check if it's a known large text field\n const largeTextFields = ['Prompt', 'Template', 'Notes', 'Description', \n 'Content', 'Body', 'Text', 'HTML', 'SQL'];\n \n if (largeTextFields.some(f => fieldName.toLowerCase().includes(f.toLowerCase()))) {\n // Only externalize if content is substantial (more than 100 chars or has newlines)\n return fieldValue.length > 100 || fieldValue.includes('\\n');\n }\n \n return false;\n }\n \n private async createExternalFile(\n targetDir: string,\n primaryKey: Record<string, any>,\n fieldName: string,\n content: string\n ): Promise<string> {\n // Determine file extension based on field name and content\n let extension = '.txt';\n \n if (fieldName.toLowerCase().includes('prompt')) {\n extension = '.md';\n } else if (fieldName.toLowerCase().includes('template')) {\n if (content.includes('<html') || content.includes('<!DOCTYPE')) {\n extension = '.html';\n } else if (content.includes('{{') || content.includes('{%')) {\n extension = '.liquid';\n }\n } else if (fieldName.toLowerCase().includes('sql')) {\n extension = '.sql';\n } else if (fieldName.toLowerCase().includes('notes') || fieldName.toLowerCase().includes('description')) {\n extension = '.md';\n }\n \n const baseFileName = this.buildFileName(primaryKey, null).replace('.json', '');\n const fileName = `${baseFileName}.${fieldName.toLowerCase()}${extension}`;\n const filePath = path.join(targetDir, fileName);\n \n await fs.writeFile(filePath, content, 'utf-8');\n \n return fileName;\n }\n \n private buildFileName(primaryKey: Record<string, any>, entityConfig: any): string {\n // Use primary key values to build filename\n const keys = Object.values(primaryKey);\n \n if (keys.length === 1 && typeof keys[0] === 'string') {\n // Single string key - use as base if it's a guid\n const key = keys[0];\n if (key.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {\n // It's a GUID, use first 8 chars\n return `${key.substring(0, 8)}.json`;\n }\n // Use the whole key if not too long\n if (key.length <= 50) {\n return `${key.replace(/[^a-zA-Z0-9-_]/g, '_')}.json`;\n }\n }\n \n // Multiple keys or numeric - create composite name\n return keys.map(k => String(k).replace(/[^a-zA-Z0-9-_]/g, '_')).join('-') + '.json';\n }\n \n private async pullRelatedEntities(\n parentRecord: any,\n relatedConfig: Record<string, RelatedEntityConfig>,\n syncEngine: SyncEngine\n ): Promise<Record<string, RecordData[]>> {\n const relatedEntities: Record<string, RecordData[]> = {};\n \n for (const [key, config] of Object.entries(relatedConfig)) {\n try {\n // Get the parent's primary key value\n const parentKeyValue = parentRecord[config.foreignKey];\n if (!parentKeyValue) {\n continue; // Skip if parent doesn't have the foreign key field\n }\n \n // Build filter for related records\n let filter = `${config.foreignKey} = '${String(parentKeyValue).replace(/'/g, \"''\")}'`;\n if (config.filter) {\n filter += ` AND (${config.filter})`;\n }\n \n // Pull related records\n const rv = new RunView();\n const result = await rv.RunView({\n EntityName: config.entity,\n ExtraFilter: filter\n }, getSystemUser());\n \n if (!result.Success) {\n this.warn(`Failed to pull related ${config.entity}: ${result.ErrorMessage}`);\n continue;\n }\n \n // Process each related record\n const relatedRecords: RecordData[] = [];\n for (const relatedRecord of result.Results) {\n const recordData: RecordData = {\n fields: {}\n };\n \n // Process fields, omitting the foreign key since it will be set via @parent\n for (const [fieldName, fieldValue] of Object.entries(relatedRecord)) {\n // Skip internal fields\n if (fieldName.startsWith('__mj_')) {\n continue;\n }\n \n // Convert foreign key reference to @parent\n if (fieldName === config.foreignKey) {\n const parentFieldName = this.findParentField(parentRecord, parentKeyValue);\n if (parentFieldName) {\n recordData.fields[fieldName] = `@parent:${parentFieldName}`;\n }\n continue;\n }\n \n recordData.fields[fieldName] = fieldValue;\n }\n \n // Pull nested related entities if configured\n if (config.relatedEntities) {\n recordData.relatedEntities = await this.pullRelatedEntities(\n relatedRecord,\n config.relatedEntities,\n syncEngine\n );\n }\n \n relatedRecords.push(recordData);\n }\n \n if (relatedRecords.length > 0) {\n relatedEntities[key] = relatedRecords;\n }\n } catch (error) {\n this.warn(`Error pulling related ${key}: ${error}`);\n }\n }\n \n return relatedEntities;\n }\n \n private findParentField(parentRecord: any, value: any): string | null {\n // Find which field in the parent contains this value\n // Typically this will be the primary key field\n for (const [fieldName, fieldValue] of Object.entries(parentRecord)) {\n if (fieldValue === value && !fieldName.startsWith('__mj_')) {\n return fieldName;\n }\n }\n return null;\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/pull/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pull command implementation for MetadataSync\n * @module commands/pull\n * \n * This module implements the pull command which retrieves metadata records from\n * the MemberJunction database and saves them as local JSON files. It supports:\n * - Filtering records with SQL expressions\n * - Pulling related entities with foreign key relationships\n * - Externalizing large text fields to separate files\n * - Creating multi-record JSON files\n * - Recursive directory search for entity configurations\n */\n\nimport { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { select } from '@inquirer/prompts';\nimport ora from 'ora-classic';\nimport { loadMJConfig, loadEntityConfig, RelatedEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { RunView } from '@memberjunction/core';\nimport { getSystemUser, initializeProvider, cleanupProvider } from '../../lib/provider-utils';\n\n/**\n * Pull metadata records from database to local files\n * \n * @class Pull\n * @extends Command\n * \n * @example\n * ```bash\n * # Pull all records for an entity\n * mj-sync pull --entity=\"AI Prompts\"\n * \n * # Pull with filter\n * mj-sync pull --entity=\"AI Prompts\" --filter=\"CategoryID='123'\"\n * \n * # Pull to multi-record file\n * mj-sync pull --entity=\"AI Prompts\" --multi-file=\"all-prompts.json\"\n * ```\n */\nexport default class Pull extends Command {\n static description = 'Pull metadata from database to local files';\n \n static examples = [\n `<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\"`,\n `<%= config.bin %> <%= command.id %> --entity=\"AI Prompts\" --filter=\"CategoryID='customer-service-id'\"`,\n ];\n \n static flags = {\n entity: Flags.string({ description: 'Entity name to pull', required: true }),\n filter: Flags.string({ description: 'Additional filter for pulling specific records' }),\n 'dry-run': Flags.boolean({ description: 'Show what would be pulled without actually pulling' }),\n 'multi-file': Flags.string({ description: 'Create a single file with multiple records (provide filename)' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Pull);\n const spinner = ora();\n \n try {\n // Load MJ config\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n // Initialize data provider\n const provider = await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directory\n const entityDirs = await this.findEntityDirectories(flags.entity);\n \n if (entityDirs.length === 0) {\n this.error(`No directory found for entity \"${flags.entity}\". Run \"mj-sync init\" first.`);\n }\n \n let targetDir: string;\n if (entityDirs.length === 1) {\n targetDir = entityDirs[0];\n } else {\n // Multiple directories found, ask user\n targetDir = await select({\n message: `Multiple directories found for entity \"${flags.entity}\". Which one to use?`,\n choices: entityDirs.map(dir => ({ name: dir, value: dir }))\n });\n }\n \n const entityConfig = await loadEntityConfig(targetDir);\n if (!entityConfig) {\n this.error(`Invalid entity configuration in ${targetDir}`);\n }\n \n // Pull records\n spinner.start(`Pulling ${flags.entity} records`);\n const rv = new RunView();\n \n let filter = '';\n if (flags.filter) {\n filter = flags.filter;\n } else if (entityConfig.pull?.filter) {\n filter = entityConfig.pull.filter;\n }\n \n const result = await rv.RunView({\n EntityName: flags.entity,\n ExtraFilter: filter\n }, getSystemUser());\n \n if (!result.Success) {\n this.error(`Failed to pull records: ${result.ErrorMessage}`);\n }\n \n spinner.succeed(`Found ${result.Results.length} records`);\n \n if (flags['dry-run']) {\n this.log(`\\nDry run mode - would pull ${result.Results.length} records to ${targetDir}`);\n return;\n }\n \n // Process each record\n const entityInfo = syncEngine.getEntityInfo(flags.entity);\n if (!entityInfo) {\n this.error(`Entity information not found for: ${flags.entity}`);\n }\n \n spinner.start('Processing records');\n let processed = 0;\n \n // If multi-file flag is set, collect all records\n if (flags['multi-file']) {\n const allRecords: RecordData[] = [];\n \n for (const record of result.Results) {\n try {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = record[pk.Name];\n }\n \n // Process record for multi-file\n const recordData = await this.processRecordData(record, primaryKey, targetDir, entityConfig, syncEngine);\n allRecords.push(recordData);\n processed++;\n \n spinner.text = `Processing records (${processed}/${result.Results.length})`;\n } catch (error) {\n this.warn(`Failed to process record: ${(error as any).message || error}`);\n }\n }\n \n // Write all records to single file\n if (allRecords.length > 0) {\n const fileName = flags['multi-file'].endsWith('.json') ? flags['multi-file'] : `${flags['multi-file']}.json`;\n const filePath = path.join(targetDir, fileName);\n await fs.writeJson(filePath, allRecords, { spaces: 2 });\n spinner.succeed(`Pulled ${processed} records to ${filePath}`);\n }\n } else {\n // Original single-file-per-record logic\n for (const record of result.Results) {\n try {\n // Build primary key\n const primaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n primaryKey[pk.Name] = record[pk.Name];\n }\n \n // Process record\n await this.processRecord(record, primaryKey, targetDir, entityConfig, syncEngine);\n processed++;\n \n spinner.text = `Processing records (${processed}/${result.Results.length})`;\n } catch (error) {\n this.warn(`Failed to process record: ${(error as any).message || error}`);\n }\n }\n \n spinner.succeed(`Pulled ${processed} records to ${targetDir}`);\n }\n \n } catch (error) {\n spinner.fail('Pull failed');\n this.error(error as Error);\n } finally {\n // Clean up database connection\n await cleanupProvider();\n }\n }\n \n /**\n * Find directories containing configuration for the specified entity\n * \n * Recursively searches the current working directory for .mj-sync.json files\n * that specify the given entity name. Returns all matching directories to\n * allow user selection when multiple locations exist.\n * \n * @param entityName - Name of the entity to search for\n * @returns Promise resolving to array of directory paths\n * @private\n */\n private async findEntityDirectories(entityName: string): Promise<string[]> {\n const dirs: string[] = [];\n \n // Search for directories with matching entity config\n const searchDirs = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(dir, entry.name);\n const config = await loadEntityConfig(fullPath);\n \n if (config && config.entity === entityName) {\n dirs.push(fullPath);\n } else {\n // Recurse\n await searchDirs(fullPath);\n }\n }\n }\n };\n \n await searchDirs(process.cwd());\n return dirs;\n }\n \n /**\n * Process a single record and save to file\n * \n * Converts a database record into the file format and writes it to disk.\n * This is a wrapper around processRecordData that handles file writing.\n * \n * @param record - Raw database record\n * @param primaryKey - Primary key fields and values\n * @param targetDir - Directory to save the file\n * @param entityConfig - Entity configuration with pull settings\n * @param syncEngine - Sync engine instance\n * @returns Promise that resolves when file is written\n * @private\n */\n private async processRecord(\n record: any, \n primaryKey: Record<string, any>,\n targetDir: string, \n entityConfig: any,\n syncEngine: SyncEngine\n ): Promise<void> {\n const recordData = await this.processRecordData(record, primaryKey, targetDir, entityConfig, syncEngine);\n \n // Determine file path\n const fileName = this.buildFileName(primaryKey, entityConfig);\n const filePath = path.join(targetDir, fileName);\n \n // Write JSON file\n await fs.writeJson(filePath, recordData, { spaces: 2 });\n }\n \n /**\n * Process record data for storage\n * \n * Transforms a raw database record into the RecordData format used for file storage.\n * Handles field externalization, related entity pulling, and checksum calculation.\n * \n * @param record - Raw database record\n * @param primaryKey - Primary key fields and values \n * @param targetDir - Directory where files will be saved\n * @param entityConfig - Entity configuration with defaults and settings\n * @param syncEngine - Sync engine for checksum calculation\n * @returns Promise resolving to formatted RecordData\n * @private\n */\n private async processRecordData(\n record: any, \n primaryKey: Record<string, any>,\n targetDir: string, \n entityConfig: any,\n syncEngine: SyncEngine\n ): Promise<RecordData> {\n // Build record data\n const recordData: RecordData = {\n primaryKey: primaryKey,\n fields: {},\n sync: {\n lastModified: new Date().toISOString(),\n checksum: ''\n }\n };\n \n // Process fields\n for (const [fieldName, fieldValue] of Object.entries(record)) {\n // Skip primary key fields\n if (primaryKey[fieldName] !== undefined) {\n continue;\n }\n \n // Skip internal fields\n if (fieldName.startsWith('__mj_')) {\n continue;\n }\n \n // Check if this is an external file field\n if (await this.shouldExternalizeField(fieldName, fieldValue, entityConfig)) {\n const fileName = await this.createExternalFile(\n targetDir,\n primaryKey,\n fieldName,\n String(fieldValue)\n );\n recordData.fields[fieldName] = `@file:${fileName}`;\n } else {\n recordData.fields[fieldName] = fieldValue;\n }\n }\n \n // Pull related entities if configured\n if (entityConfig.pull?.relatedEntities) {\n recordData.relatedEntities = await this.pullRelatedEntities(\n record,\n entityConfig.pull.relatedEntities,\n syncEngine\n );\n }\n \n // Calculate checksum\n recordData.sync!.checksum = syncEngine.calculateChecksum(recordData.fields);\n \n return recordData;\n }\n \n /**\n * Determine if a field should be saved to an external file\n * \n * Checks if a field contains substantial text content that would be better\n * stored in a separate file rather than inline in the JSON. Uses heuristics\n * based on field name and content length.\n * \n * @param fieldName - Name of the field to check\n * @param fieldValue - Value of the field\n * @param entityConfig - Entity configuration (for future extension)\n * @returns Promise resolving to true if field should be externalized\n * @private\n */\n private async shouldExternalizeField(\n fieldName: string, \n fieldValue: any,\n entityConfig: any\n ): Promise<boolean> {\n // Only externalize string fields with significant content\n if (typeof fieldValue !== 'string') {\n return false;\n }\n \n // Check if it's a known large text field\n const largeTextFields = ['Prompt', 'Template', 'Notes', 'Description', \n 'Content', 'Body', 'Text', 'HTML', 'SQL'];\n \n if (largeTextFields.some(f => fieldName.toLowerCase().includes(f.toLowerCase()))) {\n // Only externalize if content is substantial (more than 100 chars or has newlines)\n return fieldValue.length > 100 || fieldValue.includes('\\n');\n }\n \n return false;\n }\n \n /**\n * Create an external file for a field value\n * \n * Saves large text content to a separate file and returns the filename.\n * Automatically determines appropriate file extension based on field name\n * and content type (e.g., .md for prompts, .html for templates).\n * \n * @param targetDir - Directory to save the file\n * @param primaryKey - Primary key for filename generation\n * @param fieldName - Name of the field being externalized\n * @param content - Content to write to the file\n * @returns Promise resolving to the created filename\n * @private\n */\n private async createExternalFile(\n targetDir: string,\n primaryKey: Record<string, any>,\n fieldName: string,\n content: string\n ): Promise<string> {\n // Determine file extension based on field name and content\n let extension = '.txt';\n \n if (fieldName.toLowerCase().includes('prompt')) {\n extension = '.md';\n } else if (fieldName.toLowerCase().includes('template')) {\n if (content.includes('<html') || content.includes('<!DOCTYPE')) {\n extension = '.html';\n } else if (content.includes('{{') || content.includes('{%')) {\n extension = '.liquid';\n }\n } else if (fieldName.toLowerCase().includes('sql')) {\n extension = '.sql';\n } else if (fieldName.toLowerCase().includes('notes') || fieldName.toLowerCase().includes('description')) {\n extension = '.md';\n }\n \n const baseFileName = this.buildFileName(primaryKey, null).replace('.json', '');\n const fileName = `${baseFileName}.${fieldName.toLowerCase()}${extension}`;\n const filePath = path.join(targetDir, fileName);\n \n await fs.writeFile(filePath, content, 'utf-8');\n \n return fileName;\n }\n \n /**\n * Build a filename from primary key values\n * \n * Creates a safe filename based on the entity's primary key values.\n * Handles GUIDs by using first 8 characters, sanitizes special characters,\n * and creates composite names for multi-field keys.\n * \n * @param primaryKey - Primary key fields and values\n * @param entityConfig - Entity configuration (for future extension)\n * @returns Filename with .json extension\n * @private\n */\n private buildFileName(primaryKey: Record<string, any>, entityConfig: any): string {\n // Use primary key values to build filename\n const keys = Object.values(primaryKey);\n \n if (keys.length === 1 && typeof keys[0] === 'string') {\n // Single string key - use as base if it's a guid\n const key = keys[0];\n if (key.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) {\n // It's a GUID, use first 8 chars\n return `${key.substring(0, 8)}.json`;\n }\n // Use the whole key if not too long\n if (key.length <= 50) {\n return `${key.replace(/[^a-zA-Z0-9-_]/g, '_')}.json`;\n }\n }\n \n // Multiple keys or numeric - create composite name\n return keys.map(k => String(k).replace(/[^a-zA-Z0-9-_]/g, '_')).join('-') + '.json';\n }\n \n /**\n * Pull related entities for a parent record\n * \n * Retrieves child records that have foreign key relationships to the parent.\n * Converts foreign key values to @parent references and supports nested\n * related entities for deep object graphs.\n * \n * @param parentRecord - Parent entity record\n * @param relatedConfig - Configuration for related entities to pull\n * @param syncEngine - Sync engine instance\n * @returns Promise resolving to map of entity names to related records\n * @private\n */\n private async pullRelatedEntities(\n parentRecord: any,\n relatedConfig: Record<string, RelatedEntityConfig>,\n syncEngine: SyncEngine\n ): Promise<Record<string, RecordData[]>> {\n const relatedEntities: Record<string, RecordData[]> = {};\n \n for (const [key, config] of Object.entries(relatedConfig)) {\n try {\n // Get the parent's primary key value\n const parentKeyValue = parentRecord[config.foreignKey];\n if (!parentKeyValue) {\n continue; // Skip if parent doesn't have the foreign key field\n }\n \n // Build filter for related records\n let filter = `${config.foreignKey} = '${String(parentKeyValue).replace(/'/g, \"''\")}'`;\n if (config.filter) {\n filter += ` AND (${config.filter})`;\n }\n \n // Pull related records\n const rv = new RunView();\n const result = await rv.RunView({\n EntityName: config.entity,\n ExtraFilter: filter\n }, getSystemUser());\n \n if (!result.Success) {\n this.warn(`Failed to pull related ${config.entity}: ${result.ErrorMessage}`);\n continue;\n }\n \n // Process each related record\n const relatedRecords: RecordData[] = [];\n for (const relatedRecord of result.Results) {\n const recordData: RecordData = {\n fields: {}\n };\n \n // Process fields, omitting the foreign key since it will be set via @parent\n for (const [fieldName, fieldValue] of Object.entries(relatedRecord)) {\n // Skip internal fields\n if (fieldName.startsWith('__mj_')) {\n continue;\n }\n \n // Convert foreign key reference to @parent\n if (fieldName === config.foreignKey) {\n const parentFieldName = this.findParentField(parentRecord, parentKeyValue);\n if (parentFieldName) {\n recordData.fields[fieldName] = `@parent:${parentFieldName}`;\n }\n continue;\n }\n \n recordData.fields[fieldName] = fieldValue;\n }\n \n // Pull nested related entities if configured\n if (config.relatedEntities) {\n recordData.relatedEntities = await this.pullRelatedEntities(\n relatedRecord,\n config.relatedEntities,\n syncEngine\n );\n }\n \n relatedRecords.push(recordData);\n }\n \n if (relatedRecords.length > 0) {\n relatedEntities[key] = relatedRecords;\n }\n } catch (error) {\n this.warn(`Error pulling related ${key}: ${error}`);\n }\n }\n \n return relatedEntities;\n }\n \n /**\n * Find which field in the parent record contains a specific value\n * \n * Used to convert foreign key references to @parent references by finding\n * the parent field that contains the foreign key value. Typically finds\n * the primary key field but can match any field.\n * \n * @param parentRecord - Parent record to search\n * @param value - Value to search for\n * @returns Field name containing the value, or null if not found\n * @private\n */\n private findParentField(parentRecord: any, value: any): string | null {\n // Find which field in the parent contains this value\n // Typically this will be the primary key field\n for (const [fieldName, fieldValue] of Object.entries(parentRecord)) {\n if (fieldValue === value && !fieldName.startsWith('__mj_')) {\n return fieldName;\n }\n }\n return null;\n }\n}"]}
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const prompts_1 = require("@inquirer/prompts");
|
|
10
9
|
const ora_classic_1 = __importDefault(require("ora-classic"));
|
|
11
10
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
12
11
|
const config_1 = require("../../config");
|
|
@@ -86,46 +85,87 @@ class Push extends core_1.Command {
|
|
|
86
85
|
}
|
|
87
86
|
async processEntityDirectory(entityDir, entityConfig, syncEngine, flags, syncConfig) {
|
|
88
87
|
const result = { created: 0, updated: 0, errors: 0 };
|
|
89
|
-
// Find
|
|
88
|
+
// Find JSON files in the current directory only (not subdirectories)
|
|
90
89
|
const pattern = entityConfig.filePattern || '*.json';
|
|
91
90
|
const jsonFiles = await (0, fast_glob_1.default)(pattern, {
|
|
92
91
|
cwd: entityDir,
|
|
93
|
-
ignore: ['.mj-sync.json', '.mj-folder.json']
|
|
92
|
+
ignore: ['.mj-sync.json', '.mj-folder.json'],
|
|
93
|
+
dot: true // Include dotfiles (files starting with .)
|
|
94
94
|
});
|
|
95
|
-
this.log(`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
95
|
+
this.log(`Processing ${jsonFiles.length} records in ${path_1.default.relative(process.cwd(), entityDir) || '.'}`);
|
|
96
|
+
// First, process all JSON files in this directory
|
|
97
|
+
await this.processJsonFiles(jsonFiles, entityDir, entityConfig, syncEngine, flags, result);
|
|
98
|
+
// Then, recursively process subdirectories
|
|
99
|
+
const entries = await fs_extra_1.default.readdir(entityDir, { withFileTypes: true });
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
102
|
+
const subDir = path_1.default.join(entityDir, entry.name);
|
|
103
|
+
// Load subdirectory config and merge with parent config
|
|
104
|
+
let subEntityConfig = { ...entityConfig };
|
|
105
|
+
const subDirConfig = await (0, config_1.loadEntityConfig)(subDir);
|
|
106
|
+
if (subDirConfig) {
|
|
107
|
+
// Check if this is a new entity type (has different entity name)
|
|
108
|
+
if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {
|
|
109
|
+
// This is a different entity type, skip it (will be processed separately)
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Merge defaults: parent defaults + subdirectory overrides
|
|
113
|
+
subEntityConfig = {
|
|
114
|
+
...entityConfig,
|
|
115
|
+
...subDirConfig,
|
|
116
|
+
defaults: {
|
|
117
|
+
...entityConfig.defaults,
|
|
118
|
+
...(subDirConfig.defaults || {})
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Process subdirectory with merged config
|
|
123
|
+
const subResult = await this.processEntityDirectory(subDir, subEntityConfig, syncEngine, flags, syncConfig);
|
|
124
|
+
result.created += subResult.created;
|
|
125
|
+
result.updated += subResult.updated;
|
|
126
|
+
result.errors += subResult.errors;
|
|
107
127
|
}
|
|
108
128
|
}
|
|
109
|
-
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
async processJsonFiles(jsonFiles, entityDir, entityConfig, syncEngine, flags, result) {
|
|
132
|
+
if (jsonFiles.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
110
135
|
const spinner = (0, ora_classic_1.default)();
|
|
111
136
|
spinner.start('Processing records');
|
|
137
|
+
let totalRecords = 0;
|
|
112
138
|
for (const file of jsonFiles) {
|
|
113
139
|
try {
|
|
114
140
|
const filePath = path_1.default.join(entityDir, file);
|
|
115
|
-
const
|
|
141
|
+
const fileContent = await fs_extra_1.default.readJson(filePath);
|
|
142
|
+
// Process templates in the loaded content
|
|
143
|
+
const processedContent = await syncEngine.processTemplates(fileContent, entityDir);
|
|
144
|
+
// Check if the file contains a single record or an array of records
|
|
145
|
+
const isArray = Array.isArray(processedContent);
|
|
146
|
+
const records = isArray ? processedContent : [processedContent];
|
|
147
|
+
totalRecords += records.length;
|
|
116
148
|
// Build and process defaults (including lookups)
|
|
117
149
|
const defaults = await syncEngine.buildDefaults(filePath, entityConfig);
|
|
118
|
-
// Process the
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
// Process each record in the file
|
|
151
|
+
for (let i = 0; i < records.length; i++) {
|
|
152
|
+
const recordData = records[i];
|
|
153
|
+
// Process the record
|
|
154
|
+
const isNew = await this.pushRecord(recordData, entityConfig.entity, path_1.default.dirname(filePath), file, defaults, syncEngine, flags['dry-run'], flags.verbose, isArray ? i : undefined);
|
|
155
|
+
if (!flags['dry-run']) {
|
|
156
|
+
if (isNew) {
|
|
157
|
+
result.created++;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
result.updated++;
|
|
161
|
+
}
|
|
126
162
|
}
|
|
163
|
+
spinner.text = `Processing records (${result.created + result.updated + result.errors}/${totalRecords})`;
|
|
164
|
+
}
|
|
165
|
+
// Write back the entire file if it's an array
|
|
166
|
+
if (isArray && !flags['dry-run']) {
|
|
167
|
+
await fs_extra_1.default.writeJson(filePath, records, { spaces: 2 });
|
|
127
168
|
}
|
|
128
|
-
spinner.text = `Processing records (${result.created + result.updated + result.errors}/${jsonFiles.length})`;
|
|
129
169
|
}
|
|
130
170
|
catch (error) {
|
|
131
171
|
result.errors++;
|
|
@@ -133,10 +173,9 @@ class Push extends core_1.Command {
|
|
|
133
173
|
this.error(`Failed to process ${file}: ${errorMessage}`, { exit: false });
|
|
134
174
|
}
|
|
135
175
|
}
|
|
136
|
-
spinner.succeed(`Processed ${jsonFiles.length}
|
|
137
|
-
return result;
|
|
176
|
+
spinner.succeed(`Processed ${totalRecords} records from ${jsonFiles.length} files`);
|
|
138
177
|
}
|
|
139
|
-
async pushRecord(recordData, entityName, baseDir, fileName, defaults, syncEngine, dryRun, verbose = false) {
|
|
178
|
+
async pushRecord(recordData, entityName, baseDir, fileName, defaults, syncEngine, dryRun, verbose = false, arrayIndex) {
|
|
140
179
|
// Load or create entity
|
|
141
180
|
let entity = null;
|
|
142
181
|
let isNew = false;
|
|
@@ -199,15 +238,18 @@ class Push extends core_1.Command {
|
|
|
199
238
|
recordData.primaryKey = newPrimaryKey;
|
|
200
239
|
}
|
|
201
240
|
}
|
|
202
|
-
// Always update sync metadata
|
|
241
|
+
// Always update sync metadata
|
|
203
242
|
// This ensures related entities are persisted with their metadata
|
|
204
243
|
recordData.sync = {
|
|
205
244
|
lastModified: new Date().toISOString(),
|
|
206
245
|
checksum: syncEngine.calculateChecksum(recordData.fields)
|
|
207
246
|
};
|
|
208
|
-
// Write back to file
|
|
209
|
-
|
|
210
|
-
|
|
247
|
+
// Write back to file only if it's a single record (not part of an array)
|
|
248
|
+
// Array records are written back in bulk after all records are processed
|
|
249
|
+
if (arrayIndex === undefined) {
|
|
250
|
+
const filePath = path_1.default.join(baseDir, fileName);
|
|
251
|
+
await fs_extra_1.default.writeJson(filePath, recordData, { spaces: 2 });
|
|
252
|
+
}
|
|
211
253
|
return isNew;
|
|
212
254
|
}
|
|
213
255
|
async processRelatedEntities(relatedEntities, parentEntity, rootEntity, baseDir, syncEngine, verbose = false, indentLevel = 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/push/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport ora from 'ora-classic';\nimport fastGlob from 'fast-glob';\nimport { loadMJConfig, loadSyncConfig, loadEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { initializeProvider, findEntityDirectories, getSystemUser } from '../../lib/provider-utils';\nimport { BaseEntity } from '@memberjunction/core';\nimport { cleanupProvider } from '../../lib/provider-utils';\n\nexport default class Push extends Command {\n static description = 'Push local file changes to the database';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --dry-run`,\n `<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"`,\n `<%= config.bin %> <%= command.id %> --ci`,\n ];\n \n static flags = {\n dir: Flags.string({ description: 'Specific entity directory to push' }),\n 'dry-run': Flags.boolean({ description: 'Show what would be pushed without actually pushing' }),\n ci: Flags.boolean({ description: 'CI mode - no prompts, fail on issues' }),\n verbose: Flags.boolean({ char: 'v', description: 'Show detailed field-level output' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Push);\n const spinner = ora();\n \n try {\n // Load configurations\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n const syncConfig = await loadSyncConfig(process.cwd());\n \n // Initialize data provider\n await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directories to process\n const entityDirs = findEntityDirectories(process.cwd(), flags.dir);\n \n if (entityDirs.length === 0) {\n this.error('No entity directories found');\n }\n \n this.log(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to process`);\n \n // Process each entity directory\n let totalCreated = 0;\n let totalUpdated = 0;\n let totalErrors = 0;\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n this.warn(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n this.log(`\\nProcessing ${entityConfig.entity} in ${entityDir}`);\n \n const result = await this.processEntityDirectory(\n entityDir,\n entityConfig,\n syncEngine,\n flags,\n syncConfig\n );\n \n totalCreated += result.created;\n totalUpdated += result.updated;\n totalErrors += result.errors;\n }\n \n // Summary\n this.log('\\n=== Push Summary ===');\n this.log(`Created: ${totalCreated}`);\n this.log(`Updated: ${totalUpdated}`);\n this.log(`Errors: ${totalErrors}`);\n \n if (totalErrors > 0 && flags.ci) {\n this.error('Push failed with errors in CI mode');\n }\n \n } catch (error) {\n spinner.fail('Push failed');\n this.error(error as Error);\n } finally {\n // Clean up database connection\n await cleanupProvider();\n }\n }\n \n private async processEntityDirectory(\n entityDir: string,\n entityConfig: any,\n syncEngine: SyncEngine,\n flags: any,\n syncConfig: any\n ): Promise<{ created: number; updated: number; errors: number }> {\n const result = { created: 0, updated: 0, errors: 0 };\n \n // Find all JSON files\n const pattern = entityConfig.filePattern || '*.json';\n const jsonFiles = await fastGlob(pattern, {\n cwd: entityDir,\n ignore: ['.mj-sync.json', '.mj-folder.json']\n });\n \n this.log(`Found ${jsonFiles.length} records to process`);\n \n if (jsonFiles.length === 0) {\n return result;\n }\n \n // Confirm if needed\n if (!flags['dry-run'] && !flags.ci && syncConfig?.push?.requireConfirmation) {\n const proceed = await confirm({\n message: `Push ${jsonFiles.length} ${entityConfig.entity} records to database?`\n });\n \n if (!proceed) {\n this.log('Push cancelled');\n return result;\n }\n }\n \n // Process each file\n const spinner = ora();\n spinner.start('Processing records');\n \n for (const file of jsonFiles) {\n try {\n const filePath = path.join(entityDir, file);\n const recordData: RecordData = await fs.readJson(filePath);\n \n // Build and process defaults (including lookups)\n const defaults = await syncEngine.buildDefaults(filePath, entityConfig);\n \n // Process the record\n const isNew = await this.pushRecord(\n recordData,\n entityConfig.entity,\n path.dirname(filePath),\n file,\n defaults,\n syncEngine,\n flags['dry-run'],\n flags.verbose\n );\n \n if (!flags['dry-run']) {\n if (isNew) {\n result.created++;\n } else {\n result.updated++;\n }\n }\n \n spinner.text = `Processing records (${result.created + result.updated + result.errors}/${jsonFiles.length})`;\n \n } catch (error) {\n result.errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.error(`Failed to process ${file}: ${errorMessage}`, { exit: false });\n }\n }\n \n spinner.succeed(`Processed ${jsonFiles.length} records`);\n return result;\n }\n \n private async pushRecord(\n recordData: RecordData,\n entityName: string,\n baseDir: string,\n fileName: string,\n defaults: Record<string, any>,\n syncEngine: SyncEngine,\n dryRun: boolean,\n verbose: boolean = false\n ): Promise<boolean> {\n // Load or create entity\n let entity: BaseEntity | null = null;\n let isNew = false;\n \n if (recordData.primaryKey) {\n entity = await syncEngine.loadEntity(entityName, recordData.primaryKey);\n }\n \n if (!entity) {\n // New record\n entity = await syncEngine.createEntityObject(entityName);\n entity.NewRecord();\n isNew = true;\n }\n \n // Apply defaults first\n for (const [field, value] of Object.entries(defaults)) {\n if (field in entity) {\n (entity as any)[field] = value;\n }\n }\n \n // Apply record fields\n for (const [field, value] of Object.entries(recordData.fields)) {\n if (field in entity) {\n try {\n const processedValue = await syncEngine.processFieldValue(value, baseDir, null, null);\n if (verbose) {\n this.log(` Setting ${field}: ${JSON.stringify(value)} -> ${JSON.stringify(processedValue)}`);\n }\n (entity as any)[field] = processedValue;\n } catch (error) {\n throw new Error(`Failed to process field '${field}': ${error}`);\n }\n } else {\n this.warn(`Field '${field}' does not exist on entity '${entityName}'`);\n }\n }\n \n if (dryRun) {\n this.log(`Would ${isNew ? 'create' : 'update'} ${entityName} record`);\n return isNew;\n }\n \n // Save the record\n const saved = await entity.Save();\n if (!saved) {\n const errors = entity.LatestResult?.Errors?.join(', ') || 'Unknown error';\n throw new Error(`Failed to save record: ${errors}`);\n }\n \n // Process related entities after saving parent\n if (recordData.relatedEntities && !dryRun) {\n await this.processRelatedEntities(\n recordData.relatedEntities,\n entity,\n entity, // root is same as parent for top level\n baseDir,\n syncEngine,\n verbose\n );\n }\n \n // Update the local file with new primary key if created\n if (isNew) {\n const entityInfo = syncEngine.getEntityInfo(entityName);\n if (entityInfo) {\n const newPrimaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n newPrimaryKey[pk.Name] = entity.Get(pk.Name);\n }\n recordData.primaryKey = newPrimaryKey;\n }\n }\n \n // Always update sync metadata and write back to file\n // This ensures related entities are persisted with their metadata\n recordData.sync = {\n lastModified: new Date().toISOString(),\n checksum: syncEngine.calculateChecksum(recordData.fields)\n };\n \n // Write back to file\n const filePath = path.join(baseDir, fileName);\n await fs.writeJson(filePath, recordData, { spaces: 2 });\n \n return isNew;\n }\n \n private async processRelatedEntities(\n relatedEntities: Record<string, RecordData[]>,\n parentEntity: BaseEntity,\n rootEntity: BaseEntity,\n baseDir: string,\n syncEngine: SyncEngine,\n verbose: boolean = false,\n indentLevel: number = 1\n ): Promise<void> {\n const indent = ' '.repeat(indentLevel);\n \n for (const [entityName, records] of Object.entries(relatedEntities)) {\n this.log(`${indent}↳ Processing ${records.length} related ${entityName} records`);\n \n for (const relatedRecord of records) {\n try {\n // Load or create entity\n let entity = null;\n let isNew = false;\n \n if (relatedRecord.primaryKey) {\n entity = await syncEngine.loadEntity(entityName, relatedRecord.primaryKey);\n }\n \n if (!entity) {\n entity = await syncEngine.createEntityObject(entityName);\n entity.NewRecord();\n isNew = true;\n }\n \n // Apply fields with parent/root context\n for (const [field, value] of Object.entries(relatedRecord.fields)) {\n if (field in entity) {\n try {\n const processedValue = await syncEngine.processFieldValue(\n value, \n baseDir, \n parentEntity, \n rootEntity\n );\n if (verbose) {\n this.log(`${indent} Setting ${field}: ${JSON.stringify(value)} -> ${JSON.stringify(processedValue)}`);\n }\n (entity as any)[field] = processedValue;\n } catch (error) {\n throw new Error(`Failed to process field '${field}' in ${entityName}: ${error}`);\n }\n } else {\n this.warn(`${indent} Field '${field}' does not exist on entity '${entityName}'`);\n }\n }\n \n // Save the related entity\n const saved = await entity.Save();\n if (!saved) {\n const errors = entity.LatestResult?.Errors?.join(', ') || 'Unknown error';\n throw new Error(`Failed to save related ${entityName}: ${errors}`);\n }\n \n if (verbose) {\n this.log(`${indent} ✓ ${isNew ? 'Created' : 'Updated'} ${entityName} record`);\n }\n \n // Update the related record with primary key and sync metadata\n const entityInfo = syncEngine.getEntityInfo(entityName);\n if (entityInfo) {\n // Update primary key if new\n if (isNew) {\n relatedRecord.primaryKey = {};\n for (const pk of entityInfo.PrimaryKeys) {\n relatedRecord.primaryKey[pk.Name] = entity.Get(pk.Name);\n }\n }\n \n // Always update sync metadata\n relatedRecord.sync = {\n lastModified: new Date().toISOString(),\n checksum: syncEngine.calculateChecksum(relatedRecord.fields)\n };\n }\n \n // Process nested related entities if any\n if (relatedRecord.relatedEntities) {\n await this.processRelatedEntities(\n relatedRecord.relatedEntities,\n entity,\n rootEntity,\n baseDir,\n syncEngine,\n verbose,\n indentLevel + 1\n );\n }\n } catch (error) {\n throw new Error(`Failed to process related ${entityName}: ${error}`);\n }\n }\n }\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/push/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport ora from 'ora-classic';\nimport fastGlob from 'fast-glob';\nimport { loadMJConfig, loadSyncConfig, loadEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { initializeProvider, findEntityDirectories, getSystemUser } from '../../lib/provider-utils';\nimport { BaseEntity } from '@memberjunction/core';\nimport { cleanupProvider } from '../../lib/provider-utils';\n\nexport default class Push extends Command {\n static description = 'Push local file changes to the database';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --dry-run`,\n `<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"`,\n `<%= config.bin %> <%= command.id %> --ci`,\n ];\n \n static flags = {\n dir: Flags.string({ description: 'Specific entity directory to push' }),\n 'dry-run': Flags.boolean({ description: 'Show what would be pushed without actually pushing' }),\n ci: Flags.boolean({ description: 'CI mode - no prompts, fail on issues' }),\n verbose: Flags.boolean({ char: 'v', description: 'Show detailed field-level output' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Push);\n const spinner = ora();\n \n try {\n // Load configurations\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n const syncConfig = await loadSyncConfig(process.cwd());\n \n // Initialize data provider\n await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directories to process\n const entityDirs = findEntityDirectories(process.cwd(), flags.dir);\n \n if (entityDirs.length === 0) {\n this.error('No entity directories found');\n }\n \n this.log(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to process`);\n \n // Process each entity directory\n let totalCreated = 0;\n let totalUpdated = 0;\n let totalErrors = 0;\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n this.warn(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n this.log(`\\nProcessing ${entityConfig.entity} in ${entityDir}`);\n \n const result = await this.processEntityDirectory(\n entityDir,\n entityConfig,\n syncEngine,\n flags,\n syncConfig\n );\n \n totalCreated += result.created;\n totalUpdated += result.updated;\n totalErrors += result.errors;\n }\n \n // Summary\n this.log('\\n=== Push Summary ===');\n this.log(`Created: ${totalCreated}`);\n this.log(`Updated: ${totalUpdated}`);\n this.log(`Errors: ${totalErrors}`);\n \n if (totalErrors > 0 && flags.ci) {\n this.error('Push failed with errors in CI mode');\n }\n \n } catch (error) {\n spinner.fail('Push failed');\n this.error(error as Error);\n } finally {\n // Clean up database connection\n await cleanupProvider();\n }\n }\n \n private async processEntityDirectory(\n entityDir: string,\n entityConfig: any,\n syncEngine: SyncEngine,\n flags: any,\n syncConfig: any\n ): Promise<{ created: number; updated: number; errors: number }> {\n const result = { created: 0, updated: 0, errors: 0 };\n \n // Find JSON files in the current directory only (not subdirectories)\n const pattern = entityConfig.filePattern || '*.json';\n const jsonFiles = await fastGlob(pattern, {\n cwd: entityDir,\n ignore: ['.mj-sync.json', '.mj-folder.json'],\n dot: true // Include dotfiles (files starting with .)\n });\n \n this.log(`Processing ${jsonFiles.length} records in ${path.relative(process.cwd(), entityDir) || '.'}`);\n \n // First, process all JSON files in this directory\n await this.processJsonFiles(jsonFiles, entityDir, entityConfig, syncEngine, flags, result);\n \n // Then, recursively process subdirectories\n const entries = await fs.readdir(entityDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const subDir = path.join(entityDir, entry.name);\n \n // Load subdirectory config and merge with parent config\n let subEntityConfig = { ...entityConfig };\n const subDirConfig = await loadEntityConfig(subDir);\n \n if (subDirConfig) {\n // Check if this is a new entity type (has different entity name)\n if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {\n // This is a different entity type, skip it (will be processed separately)\n continue;\n }\n \n // Merge defaults: parent defaults + subdirectory overrides\n subEntityConfig = {\n ...entityConfig,\n ...subDirConfig,\n defaults: {\n ...entityConfig.defaults,\n ...(subDirConfig.defaults || {})\n }\n };\n }\n \n // Process subdirectory with merged config\n const subResult = await this.processEntityDirectory(\n subDir,\n subEntityConfig,\n syncEngine,\n flags,\n syncConfig\n );\n \n result.created += subResult.created;\n result.updated += subResult.updated;\n result.errors += subResult.errors;\n }\n }\n \n return result;\n }\n \n private async processJsonFiles(\n jsonFiles: string[],\n entityDir: string,\n entityConfig: any,\n syncEngine: SyncEngine,\n flags: any,\n result: { created: number; updated: number; errors: number }\n ): Promise<void> {\n if (jsonFiles.length === 0) {\n return;\n }\n \n const spinner = ora();\n spinner.start('Processing records');\n \n let totalRecords = 0;\n \n for (const file of jsonFiles) {\n try {\n const filePath = path.join(entityDir, file);\n const fileContent = await fs.readJson(filePath);\n \n // Process templates in the loaded content\n const processedContent = await syncEngine.processTemplates(fileContent, entityDir);\n \n // Check if the file contains a single record or an array of records\n const isArray = Array.isArray(processedContent);\n const records: RecordData[] = isArray ? processedContent : [processedContent];\n totalRecords += records.length;\n \n // Build and process defaults (including lookups)\n const defaults = await syncEngine.buildDefaults(filePath, entityConfig);\n \n // Process each record in the file\n for (let i = 0; i < records.length; i++) {\n const recordData = records[i];\n \n // Process the record\n const isNew = await this.pushRecord(\n recordData,\n entityConfig.entity,\n path.dirname(filePath),\n file,\n defaults,\n syncEngine,\n flags['dry-run'],\n flags.verbose,\n isArray ? i : undefined\n );\n \n if (!flags['dry-run']) {\n if (isNew) {\n result.created++;\n } else {\n result.updated++;\n }\n }\n \n spinner.text = `Processing records (${result.created + result.updated + result.errors}/${totalRecords})`;\n }\n \n // Write back the entire file if it's an array\n if (isArray && !flags['dry-run']) {\n await fs.writeJson(filePath, records, { spaces: 2 });\n }\n \n } catch (error) {\n result.errors++;\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.error(`Failed to process ${file}: ${errorMessage}`, { exit: false });\n }\n }\n \n spinner.succeed(`Processed ${totalRecords} records from ${jsonFiles.length} files`);\n }\n \n private async pushRecord(\n recordData: RecordData,\n entityName: string,\n baseDir: string,\n fileName: string,\n defaults: Record<string, any>,\n syncEngine: SyncEngine,\n dryRun: boolean,\n verbose: boolean = false,\n arrayIndex?: number\n ): Promise<boolean> {\n // Load or create entity\n let entity: BaseEntity | null = null;\n let isNew = false;\n \n if (recordData.primaryKey) {\n entity = await syncEngine.loadEntity(entityName, recordData.primaryKey);\n }\n \n if (!entity) {\n // New record\n entity = await syncEngine.createEntityObject(entityName);\n entity.NewRecord();\n isNew = true;\n }\n \n // Apply defaults first\n for (const [field, value] of Object.entries(defaults)) {\n if (field in entity) {\n (entity as any)[field] = value;\n }\n }\n \n // Apply record fields\n for (const [field, value] of Object.entries(recordData.fields)) {\n if (field in entity) {\n try {\n const processedValue = await syncEngine.processFieldValue(value, baseDir, null, null);\n if (verbose) {\n this.log(` Setting ${field}: ${JSON.stringify(value)} -> ${JSON.stringify(processedValue)}`);\n }\n (entity as any)[field] = processedValue;\n } catch (error) {\n throw new Error(`Failed to process field '${field}': ${error}`);\n }\n } else {\n this.warn(`Field '${field}' does not exist on entity '${entityName}'`);\n }\n }\n \n if (dryRun) {\n this.log(`Would ${isNew ? 'create' : 'update'} ${entityName} record`);\n return isNew;\n }\n \n // Save the record\n const saved = await entity.Save();\n if (!saved) {\n const errors = entity.LatestResult?.Errors?.join(', ') || 'Unknown error';\n throw new Error(`Failed to save record: ${errors}`);\n }\n \n // Process related entities after saving parent\n if (recordData.relatedEntities && !dryRun) {\n await this.processRelatedEntities(\n recordData.relatedEntities,\n entity,\n entity, // root is same as parent for top level\n baseDir,\n syncEngine,\n verbose\n );\n }\n \n // Update the local file with new primary key if created\n if (isNew) {\n const entityInfo = syncEngine.getEntityInfo(entityName);\n if (entityInfo) {\n const newPrimaryKey: Record<string, any> = {};\n for (const pk of entityInfo.PrimaryKeys) {\n newPrimaryKey[pk.Name] = entity.Get(pk.Name);\n }\n recordData.primaryKey = newPrimaryKey;\n }\n }\n \n // Always update sync metadata\n // This ensures related entities are persisted with their metadata\n recordData.sync = {\n lastModified: new Date().toISOString(),\n checksum: syncEngine.calculateChecksum(recordData.fields)\n };\n \n // Write back to file only if it's a single record (not part of an array)\n // Array records are written back in bulk after all records are processed\n if (arrayIndex === undefined) {\n const filePath = path.join(baseDir, fileName);\n await fs.writeJson(filePath, recordData, { spaces: 2 });\n }\n \n return isNew;\n }\n \n private async processRelatedEntities(\n relatedEntities: Record<string, RecordData[]>,\n parentEntity: BaseEntity,\n rootEntity: BaseEntity,\n baseDir: string,\n syncEngine: SyncEngine,\n verbose: boolean = false,\n indentLevel: number = 1\n ): Promise<void> {\n const indent = ' '.repeat(indentLevel);\n \n for (const [entityName, records] of Object.entries(relatedEntities)) {\n this.log(`${indent}↳ Processing ${records.length} related ${entityName} records`);\n \n for (const relatedRecord of records) {\n try {\n // Load or create entity\n let entity = null;\n let isNew = false;\n \n if (relatedRecord.primaryKey) {\n entity = await syncEngine.loadEntity(entityName, relatedRecord.primaryKey);\n }\n \n if (!entity) {\n entity = await syncEngine.createEntityObject(entityName);\n entity.NewRecord();\n isNew = true;\n }\n \n // Apply fields with parent/root context\n for (const [field, value] of Object.entries(relatedRecord.fields)) {\n if (field in entity) {\n try {\n const processedValue = await syncEngine.processFieldValue(\n value, \n baseDir, \n parentEntity, \n rootEntity\n );\n if (verbose) {\n this.log(`${indent} Setting ${field}: ${JSON.stringify(value)} -> ${JSON.stringify(processedValue)}`);\n }\n (entity as any)[field] = processedValue;\n } catch (error) {\n throw new Error(`Failed to process field '${field}' in ${entityName}: ${error}`);\n }\n } else {\n this.warn(`${indent} Field '${field}' does not exist on entity '${entityName}'`);\n }\n }\n \n // Save the related entity\n const saved = await entity.Save();\n if (!saved) {\n const errors = entity.LatestResult?.Errors?.join(', ') || 'Unknown error';\n throw new Error(`Failed to save related ${entityName}: ${errors}`);\n }\n \n if (verbose) {\n this.log(`${indent} ✓ ${isNew ? 'Created' : 'Updated'} ${entityName} record`);\n }\n \n // Update the related record with primary key and sync metadata\n const entityInfo = syncEngine.getEntityInfo(entityName);\n if (entityInfo) {\n // Update primary key if new\n if (isNew) {\n relatedRecord.primaryKey = {};\n for (const pk of entityInfo.PrimaryKeys) {\n relatedRecord.primaryKey[pk.Name] = entity.Get(pk.Name);\n }\n }\n \n // Always update sync metadata\n relatedRecord.sync = {\n lastModified: new Date().toISOString(),\n checksum: syncEngine.calculateChecksum(relatedRecord.fields)\n };\n }\n \n // Process nested related entities if any\n if (relatedRecord.relatedEntities) {\n await this.processRelatedEntities(\n relatedRecord.relatedEntities,\n entity,\n rootEntity,\n baseDir,\n syncEngine,\n verbose,\n indentLevel + 1\n );\n }\n } catch (error) {\n throw new Error(`Failed to process related ${entityName}: ${error}`);\n }\n }\n }\n }\n}"]}
|
|
@@ -81,11 +81,12 @@ class Status extends core_1.Command {
|
|
|
81
81
|
}
|
|
82
82
|
async checkEntityDirectory(entityDir, entityConfig, syncEngine) {
|
|
83
83
|
const result = { new: 0, modified: 0, deleted: 0, unchanged: 0 };
|
|
84
|
-
// Find
|
|
84
|
+
// Find JSON files in the current directory only (not subdirectories)
|
|
85
85
|
const pattern = entityConfig.filePattern || '*.json';
|
|
86
86
|
const jsonFiles = await (0, fast_glob_1.default)(pattern, {
|
|
87
87
|
cwd: entityDir,
|
|
88
|
-
ignore: ['.mj-sync.json', '.mj-folder.json']
|
|
88
|
+
ignore: ['.mj-sync.json', '.mj-folder.json'],
|
|
89
|
+
dot: true // Include dotfiles (files starting with .)
|
|
89
90
|
});
|
|
90
91
|
for (const file of jsonFiles) {
|
|
91
92
|
try {
|
|
@@ -117,6 +118,38 @@ class Status extends core_1.Command {
|
|
|
117
118
|
this.warn(`Failed to check ${file}: ${error}`);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
121
|
+
// Recursively process subdirectories
|
|
122
|
+
const entries = await fs_extra_1.default.readdir(entityDir, { withFileTypes: true });
|
|
123
|
+
for (const entry of entries) {
|
|
124
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
125
|
+
const subDir = path_1.default.join(entityDir, entry.name);
|
|
126
|
+
// Load subdirectory config and merge with parent config
|
|
127
|
+
let subEntityConfig = { ...entityConfig };
|
|
128
|
+
const subDirConfig = await (0, config_1.loadEntityConfig)(subDir);
|
|
129
|
+
if (subDirConfig) {
|
|
130
|
+
// Check if this is a new entity type (has different entity name)
|
|
131
|
+
if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {
|
|
132
|
+
// This is a different entity type, skip it (will be processed separately)
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
// Merge defaults: parent defaults + subdirectory overrides
|
|
136
|
+
subEntityConfig = {
|
|
137
|
+
...entityConfig,
|
|
138
|
+
...subDirConfig,
|
|
139
|
+
defaults: {
|
|
140
|
+
...entityConfig.defaults,
|
|
141
|
+
...(subDirConfig.defaults || {})
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// Process subdirectory with merged config
|
|
146
|
+
const subResult = await this.checkEntityDirectory(subDir, subEntityConfig, syncEngine);
|
|
147
|
+
result.new += subResult.new;
|
|
148
|
+
result.modified += subResult.modified;
|
|
149
|
+
result.deleted += subResult.deleted;
|
|
150
|
+
result.unchanged += subResult.unchanged;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
120
153
|
return result;
|
|
121
154
|
}
|
|
122
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport fastGlob from 'fast-glob';\nimport ora from 'ora-classic';\nimport { loadMJConfig, loadEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { initializeProvider, findEntityDirectories, getSystemUser } from '../../lib/provider-utils';\n\nexport default class Status extends Command {\n static description = 'Show status of local files vs database';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"`,\n ];\n \n static flags = {\n dir: Flags.string({ description: 'Specific entity directory to check status' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Status);\n const spinner = ora();\n \n try {\n // Load configurations\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n // Initialize data provider\n const provider = await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directories to process\n const entityDirs = findEntityDirectories(process.cwd(), flags.dir);\n \n if (entityDirs.length === 0) {\n this.error('No entity directories found');\n }\n \n this.log(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to check`);\n \n // Process each entity directory\n let totalNew = 0;\n let totalModified = 0;\n let totalDeleted = 0;\n let totalUnchanged = 0;\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n this.warn(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n this.log(`\\nChecking ${entityConfig.entity} in ${entityDir}`);\n \n const result = await this.checkEntityDirectory(\n entityDir,\n entityConfig,\n syncEngine\n );\n \n totalNew += result.new;\n totalModified += result.modified;\n totalDeleted += result.deleted;\n totalUnchanged += result.unchanged;\n \n // Show directory summary\n if (result.new > 0 || result.modified > 0 || result.deleted > 0) {\n this.log(` New: ${result.new}, Modified: ${result.modified}, Deleted: ${result.deleted}, Unchanged: ${result.unchanged}`);\n } else {\n this.log(` All ${result.unchanged} records are up to date`);\n }\n }\n \n // Overall summary\n this.log('\\n=== Status Summary ===');\n this.log(`New (local only): ${totalNew}`);\n this.log(`Modified locally: ${totalModified}`);\n this.log(`Deleted locally: ${totalDeleted}`);\n this.log(`Unchanged: ${totalUnchanged}`);\n \n } catch (error) {\n spinner.fail('Status check failed');\n this.error(error as Error);\n }\n }\n \n private async checkEntityDirectory(\n entityDir: string,\n entityConfig: any,\n syncEngine: SyncEngine\n ): Promise<{ new: number; modified: number; deleted: number; unchanged: number }> {\n const result = { new: 0, modified: 0, deleted: 0, unchanged: 0 };\n \n // Find all JSON files\n const pattern = entityConfig.filePattern || '*.json';\n const jsonFiles = await fastGlob(pattern, {\n cwd: entityDir,\n ignore: ['.mj-sync.json', '.mj-folder.json']\n });\n \n for (const file of jsonFiles) {\n try {\n const filePath = path.join(entityDir, file);\n const recordData: RecordData = await fs.readJson(filePath);\n \n if (recordData.primaryKey) {\n // Check if record exists in database\n const entity = await syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);\n \n if (!entity) {\n result.deleted++;\n } else {\n // Check if modified\n const currentChecksum = syncEngine.calculateChecksum(recordData.fields);\n if (recordData.sync?.checksum !== currentChecksum) {\n result.modified++;\n } else {\n result.unchanged++;\n }\n }\n } else {\n // New record\n result.new++;\n }\n \n } catch (error) {\n this.warn(`Failed to check ${file}: ${error}`);\n }\n }\n \n return result;\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport fastGlob from 'fast-glob';\nimport ora from 'ora-classic';\nimport { loadMJConfig, loadEntityConfig } from '../../config';\nimport { SyncEngine, RecordData } from '../../lib/sync-engine';\nimport { initializeProvider, findEntityDirectories, getSystemUser } from '../../lib/provider-utils';\n\nexport default class Status extends Command {\n static description = 'Show status of local files vs database';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --dir=\"ai-prompts\"`,\n ];\n \n static flags = {\n dir: Flags.string({ description: 'Specific entity directory to check status' }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(Status);\n const spinner = ora();\n \n try {\n // Load configurations\n spinner.start('Loading configuration');\n const mjConfig = loadMJConfig();\n if (!mjConfig) {\n this.error('No mj.config.cjs found in current directory or parent directories');\n }\n \n // Initialize data provider\n const provider = await initializeProvider(mjConfig);\n \n // Initialize sync engine\n const syncEngine = new SyncEngine(getSystemUser());\n await syncEngine.initialize();\n spinner.succeed('Configuration loaded');\n \n // Find entity directories to process\n const entityDirs = findEntityDirectories(process.cwd(), flags.dir);\n \n if (entityDirs.length === 0) {\n this.error('No entity directories found');\n }\n \n this.log(`Found ${entityDirs.length} entity ${entityDirs.length === 1 ? 'directory' : 'directories'} to check`);\n \n // Process each entity directory\n let totalNew = 0;\n let totalModified = 0;\n let totalDeleted = 0;\n let totalUnchanged = 0;\n \n for (const entityDir of entityDirs) {\n const entityConfig = await loadEntityConfig(entityDir);\n if (!entityConfig) {\n this.warn(`Skipping ${entityDir} - no valid entity configuration`);\n continue;\n }\n \n this.log(`\\nChecking ${entityConfig.entity} in ${entityDir}`);\n \n const result = await this.checkEntityDirectory(\n entityDir,\n entityConfig,\n syncEngine\n );\n \n totalNew += result.new;\n totalModified += result.modified;\n totalDeleted += result.deleted;\n totalUnchanged += result.unchanged;\n \n // Show directory summary\n if (result.new > 0 || result.modified > 0 || result.deleted > 0) {\n this.log(` New: ${result.new}, Modified: ${result.modified}, Deleted: ${result.deleted}, Unchanged: ${result.unchanged}`);\n } else {\n this.log(` All ${result.unchanged} records are up to date`);\n }\n }\n \n // Overall summary\n this.log('\\n=== Status Summary ===');\n this.log(`New (local only): ${totalNew}`);\n this.log(`Modified locally: ${totalModified}`);\n this.log(`Deleted locally: ${totalDeleted}`);\n this.log(`Unchanged: ${totalUnchanged}`);\n \n } catch (error) {\n spinner.fail('Status check failed');\n this.error(error as Error);\n }\n }\n \n private async checkEntityDirectory(\n entityDir: string,\n entityConfig: any,\n syncEngine: SyncEngine\n ): Promise<{ new: number; modified: number; deleted: number; unchanged: number }> {\n const result = { new: 0, modified: 0, deleted: 0, unchanged: 0 };\n \n // Find JSON files in the current directory only (not subdirectories)\n const pattern = entityConfig.filePattern || '*.json';\n const jsonFiles = await fastGlob(pattern, {\n cwd: entityDir,\n ignore: ['.mj-sync.json', '.mj-folder.json'],\n dot: true // Include dotfiles (files starting with .)\n });\n \n for (const file of jsonFiles) {\n try {\n const filePath = path.join(entityDir, file);\n const recordData: RecordData = await fs.readJson(filePath);\n \n if (recordData.primaryKey) {\n // Check if record exists in database\n const entity = await syncEngine.loadEntity(entityConfig.entity, recordData.primaryKey);\n \n if (!entity) {\n result.deleted++;\n } else {\n // Check if modified\n const currentChecksum = syncEngine.calculateChecksum(recordData.fields);\n if (recordData.sync?.checksum !== currentChecksum) {\n result.modified++;\n } else {\n result.unchanged++;\n }\n }\n } else {\n // New record\n result.new++;\n }\n \n } catch (error) {\n this.warn(`Failed to check ${file}: ${error}`);\n }\n }\n \n // Recursively process subdirectories\n const entries = await fs.readdir(entityDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.')) {\n const subDir = path.join(entityDir, entry.name);\n \n // Load subdirectory config and merge with parent config\n let subEntityConfig = { ...entityConfig };\n const subDirConfig = await loadEntityConfig(subDir);\n \n if (subDirConfig) {\n // Check if this is a new entity type (has different entity name)\n if (subDirConfig.entity && subDirConfig.entity !== entityConfig.entity) {\n // This is a different entity type, skip it (will be processed separately)\n continue;\n }\n \n // Merge defaults: parent defaults + subdirectory overrides\n subEntityConfig = {\n ...entityConfig,\n ...subDirConfig,\n defaults: {\n ...entityConfig.defaults,\n ...(subDirConfig.defaults || {})\n }\n };\n }\n \n // Process subdirectory with merged config\n const subResult = await this.checkEntityDirectory(\n subDir,\n subEntityConfig,\n syncEngine\n );\n \n result.new += subResult.new;\n result.modified += subResult.modified;\n result.deleted += subResult.deleted;\n result.unchanged += subResult.unchanged;\n }\n }\n \n return result;\n }\n}"]}
|
|
@@ -57,7 +57,7 @@ class Watch extends core_1.Command {
|
|
|
57
57
|
this.log(`Watching ${entityConfig.entity} in ${entityDir}`);
|
|
58
58
|
// Watch for JSON files and external files
|
|
59
59
|
const patterns = [
|
|
60
|
-
path_1.default.join(entityDir, entityConfig.filePattern || '
|
|
60
|
+
path_1.default.join(entityDir, entityConfig.filePattern || '**/*.json'),
|
|
61
61
|
path_1.default.join(entityDir, '**/*.md'),
|
|
62
62
|
path_1.default.join(entityDir, '**/*.txt'),
|
|
63
63
|
path_1.default.join(entityDir, '**/*.html'),
|