@rvoh/psychic 0.37.2 → 0.37.4

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.
@@ -41,11 +41,17 @@ async function syncTypescriptOpenapiFiles() {
41
41
  const outpath = path.join((0, psychicPath_js_1.default)('types'), `${jsonPath.replace(/\.json$/, '')}.d.ts`);
42
42
  return dream_1.DreamCLI.spawn(`npx openapi-typescript ${jsonPath} -o ${outpath}`).then(async () => {
43
43
  const file = (await fs.readFile(outpath)).toString();
44
- const exportName = (0, dream_1.camelize)(jsonPath
44
+ const exportName = dotToCamelCase((0, dream_1.camelize)(jsonPath
45
45
  .split('/')
46
46
  .at(-1)
47
- ?.replace(/\.json/, '')) + 'Paths';
47
+ ?.replace(/\.json/, ''))) + 'Paths';
48
48
  await fs.writeFile(outpath, file.replace(/export interface paths/, `export interface ${exportName}`));
49
49
  });
50
50
  }));
51
51
  }
52
+ function dotToCamelCase(inputString) {
53
+ return inputString
54
+ .split('.')
55
+ .map((word, index) => (index === 0 ? word : (0, dream_1.capitalize)(word)))
56
+ .join('');
57
+ }
@@ -8,6 +8,7 @@ const index_js_1 = __importDefault(require("../bin/index.js"));
8
8
  const syncEnums_js_1 = __importDefault(require("../generate/initializer/syncEnums.js"));
9
9
  const syncOpenapiTypescript_js_1 = __importDefault(require("../generate/initializer/syncOpenapiTypescript.js"));
10
10
  const reduxBindings_js_1 = __importDefault(require("../generate/openapi/reduxBindings.js"));
11
+ const Watcher_js_1 = __importDefault(require("../watcher/Watcher.js"));
11
12
  class PsychicCLI {
12
13
  static provide(program, { initializePsychicApp, seedDb, }) {
13
14
  dream_1.DreamCLI.generateDreamCli(program, {
@@ -98,6 +99,14 @@ class PsychicCLI {
98
99
  await index_js_1.default.sync();
99
100
  process.exit();
100
101
  });
102
+ program
103
+ .command('watch')
104
+ .description('watches your app for changes, and re-syncs any time they happen')
105
+ .argument('[dir]', 'the folder you want to watch, defaults to ./src')
106
+ .action(async (dir) => {
107
+ await initializePsychicApp();
108
+ Watcher_js_1.default.watch(dir);
109
+ });
101
110
  program
102
111
  .command('post-sync')
103
112
  .description('an internal command that runs as the second stage of the `sync` command, since after types are rebuit, the application needs to be reloaded before autogenerating certain files, since those files will need to leverage the updated types')
@@ -1,9 +1,33 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.default = default_1;
30
+ const path = __importStar(require("path"));
7
31
  const dream_1 = require("@rvoh/dream");
8
32
  const index_js_1 = __importDefault(require("../../psychic-app/index.js"));
9
33
  function default_1(dreamPathType) {
@@ -17,6 +41,9 @@ function default_1(dreamPathType) {
17
41
  return psychicApp.paths.controllerSpecs;
18
42
  case 'services':
19
43
  return psychicApp.paths.services;
44
+ case 'src':
45
+ // TODO: make this customizable, but maybe not.
46
+ return path.join((0, dream_1.dreamPath)('db'), '..');
20
47
  default:
21
48
  return (0, dream_1.dreamPath)(dreamPathType);
22
49
  }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const dream_1 = require("@rvoh/dream");
30
+ const fs = __importStar(require("fs"));
31
+ const psychicPath_js_1 = __importDefault(require("../helpers/path/psychicPath.js"));
32
+ const index_js_1 = __importDefault(require("../psychic-app/index.js"));
33
+ // should we make this customizable?
34
+ const TIMEOUT_INTERVAL = 3_000;
35
+ class Watcher {
36
+ static syncing = false;
37
+ static watch(
38
+ // the path to the src folder in your psychic app
39
+ srcDir = (0, psychicPath_js_1.default)('src')) {
40
+ let timer;
41
+ fs.watch(srcDir, { recursive: true }, (_, filename) => {
42
+ // do not want to sync if we are already syncing.
43
+ if (this.syncing)
44
+ return;
45
+ if (filename && /\.ts$/.test(filename)) {
46
+ // create a manual debounce pattern by clearing
47
+ // the timeout and restarting it
48
+ clearTimeout(timer);
49
+ const seconds = TIMEOUT_INTERVAL / 1000;
50
+ dream_1.DreamCLI.logger.log(`${filename} changed, douncing sync for ${seconds} seconds...`);
51
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
52
+ timer = setTimeout(async () => {
53
+ dream_1.DreamCLI.logger.log(`executing sync...`);
54
+ const psy = index_js_1.default.getOrFail();
55
+ this.syncing = true;
56
+ await dream_1.DreamCLI.spawn(psy.psyCmd('sync'));
57
+ // pause for an additional second, so that any file changes
58
+ // still being regestered from the end of the sync
59
+ // command don't accidentally trick it into running again,
60
+ // which could cause an infinite loop of reloading
61
+ setTimeout(() => {
62
+ this.syncing = false;
63
+ dream_1.DreamCLI.logger.log(`resuming watch...`);
64
+ }, 1000);
65
+ }, TIMEOUT_INTERVAL);
66
+ }
67
+ });
68
+ dream_1.DreamCLI.logger.log(`watching ${srcDir}...`);
69
+ }
70
+ }
71
+ exports.default = Watcher;
@@ -1,4 +1,4 @@
1
- import { camelize, DreamCLI } from '@rvoh/dream';
1
+ import { camelize, capitalize, DreamCLI } from '@rvoh/dream';
2
2
  import * as fs from 'node:fs/promises';
3
3
  import * as path from 'node:path';
4
4
  import PsychicApp from '../../psychic-app/index.js';
@@ -12,11 +12,17 @@ export default async function syncTypescriptOpenapiFiles() {
12
12
  const outpath = path.join(psychicPath('types'), `${jsonPath.replace(/\.json$/, '')}.d.ts`);
13
13
  return DreamCLI.spawn(`npx openapi-typescript ${jsonPath} -o ${outpath}`).then(async () => {
14
14
  const file = (await fs.readFile(outpath)).toString();
15
- const exportName = camelize(jsonPath
15
+ const exportName = dotToCamelCase(camelize(jsonPath
16
16
  .split('/')
17
17
  .at(-1)
18
- ?.replace(/\.json/, '')) + 'Paths';
18
+ ?.replace(/\.json/, ''))) + 'Paths';
19
19
  await fs.writeFile(outpath, file.replace(/export interface paths/, `export interface ${exportName}`));
20
20
  });
21
21
  }));
22
22
  }
23
+ function dotToCamelCase(inputString) {
24
+ return inputString
25
+ .split('.')
26
+ .map((word, index) => (index === 0 ? word : capitalize(word)))
27
+ .join('');
28
+ }
@@ -3,6 +3,7 @@ import PsychicBin from '../bin/index.js';
3
3
  import generateSyncEnumsInitializer from '../generate/initializer/syncEnums.js';
4
4
  import generateSyncOpenapiTypescriptInitializer from '../generate/initializer/syncOpenapiTypescript.js';
5
5
  import generateOpenapiReduxBindings from '../generate/openapi/reduxBindings.js';
6
+ import Watcher from '../watcher/Watcher.js';
6
7
  export default class PsychicCLI {
7
8
  static provide(program, { initializePsychicApp, seedDb, }) {
8
9
  DreamCLI.generateDreamCli(program, {
@@ -93,6 +94,14 @@ export default class PsychicCLI {
93
94
  await PsychicBin.sync();
94
95
  process.exit();
95
96
  });
97
+ program
98
+ .command('watch')
99
+ .description('watches your app for changes, and re-syncs any time they happen')
100
+ .argument('[dir]', 'the folder you want to watch, defaults to ./src')
101
+ .action(async (dir) => {
102
+ await initializePsychicApp();
103
+ Watcher.watch(dir);
104
+ });
96
105
  program
97
106
  .command('post-sync')
98
107
  .description('an internal command that runs as the second stage of the `sync` command, since after types are rebuit, the application needs to be reloaded before autogenerating certain files, since those files will need to leverage the updated types')
@@ -1,3 +1,4 @@
1
+ import * as path from 'path';
1
2
  import { dreamPath } from '@rvoh/dream';
2
3
  import PsychicApp from '../../psychic-app/index.js';
3
4
  export default function (dreamPathType) {
@@ -11,6 +12,9 @@ export default function (dreamPathType) {
11
12
  return psychicApp.paths.controllerSpecs;
12
13
  case 'services':
13
14
  return psychicApp.paths.services;
15
+ case 'src':
16
+ // TODO: make this customizable, but maybe not.
17
+ return path.join(dreamPath('db'), '..');
14
18
  default:
15
19
  return dreamPath(dreamPathType);
16
20
  }
@@ -0,0 +1,42 @@
1
+ import { DreamCLI } from '@rvoh/dream';
2
+ import * as fs from 'fs';
3
+ import psychicPath from '../helpers/path/psychicPath.js';
4
+ import PsychicApp from '../psychic-app/index.js';
5
+ // should we make this customizable?
6
+ const TIMEOUT_INTERVAL = 3_000;
7
+ export default class Watcher {
8
+ static syncing = false;
9
+ static watch(
10
+ // the path to the src folder in your psychic app
11
+ srcDir = psychicPath('src')) {
12
+ let timer;
13
+ fs.watch(srcDir, { recursive: true }, (_, filename) => {
14
+ // do not want to sync if we are already syncing.
15
+ if (this.syncing)
16
+ return;
17
+ if (filename && /\.ts$/.test(filename)) {
18
+ // create a manual debounce pattern by clearing
19
+ // the timeout and restarting it
20
+ clearTimeout(timer);
21
+ const seconds = TIMEOUT_INTERVAL / 1000;
22
+ DreamCLI.logger.log(`${filename} changed, douncing sync for ${seconds} seconds...`);
23
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
24
+ timer = setTimeout(async () => {
25
+ DreamCLI.logger.log(`executing sync...`);
26
+ const psy = PsychicApp.getOrFail();
27
+ this.syncing = true;
28
+ await DreamCLI.spawn(psy.psyCmd('sync'));
29
+ // pause for an additional second, so that any file changes
30
+ // still being regestered from the end of the sync
31
+ // command don't accidentally trick it into running again,
32
+ // which could cause an infinite loop of reloading
33
+ setTimeout(() => {
34
+ this.syncing = false;
35
+ DreamCLI.logger.log(`resuming watch...`);
36
+ }, 1000);
37
+ }, TIMEOUT_INTERVAL);
38
+ }
39
+ });
40
+ DreamCLI.logger.log(`watching ${srcDir}...`);
41
+ }
42
+ }
@@ -1,4 +1,4 @@
1
- export default function (dreamPathType: PsychicPaths): string;
1
+ export default function (dreamPathType: PsychicPaths | 'src'): string;
2
2
  type DreamPaths = 'models' | 'modelSpecs' | 'serializers' | 'db' | 'conf' | 'factories' | 'types';
3
3
  export type PsychicPaths = DreamPaths | 'apiRoutes' | 'controllers' | 'controllerSpecs' | 'services';
4
4
  export {};
@@ -0,0 +1,4 @@
1
+ export default class Watcher {
2
+ private static syncing;
3
+ static watch(srcDir?: string): void;
4
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@rvoh/psychic",
4
4
  "description": "Typescript web framework",
5
- "version": "0.37.2",
5
+ "version": "0.37.4",
6
6
  "author": "RVOHealth",
7
7
  "repository": {
8
8
  "type": "git",