@keycloakify/angular 0.0.11 → 0.1.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.
Files changed (60) hide show
  1. package/bin/108.index.js +242 -0
  2. package/bin/338.index.js +104 -54
  3. package/bin/402.index.js +1250 -0
  4. package/bin/758.index.js +777 -53
  5. package/bin/{925.index.js → 84.index.js} +124 -624
  6. package/bin/main.js +59 -4
  7. package/package.json +1 -1
  8. package/src/bin/add-story.ts +126 -0
  9. package/src/bin/eject-page.ts +49 -11
  10. package/src/bin/main.ts +2 -4
  11. package/src/bin/tools/nodeModulesBinDirPath.ts +38 -0
  12. package/src/bin/tools/runPrettier.ts +89 -0
  13. package/src/bin/tools/transformCodebase_async.ts +89 -0
  14. package/src/bin/update-kc-gen.ts +20 -15
  15. package/stories/account/pages/account.stories.ts +133 -0
  16. package/stories/account/pages/applications.stories.ts +196 -0
  17. package/stories/account/pages/federated-identity.stories.ts +78 -0
  18. package/stories/account/pages/log.stories.ts +147 -0
  19. package/stories/account/pages/password.stories.ts +104 -0
  20. package/stories/account/pages/sessions.stories.ts +143 -0
  21. package/stories/account/pages/totp.stories.ts +100 -0
  22. package/stories/login/pages/code.stories.ts +51 -0
  23. package/stories/login/pages/delete-account-confirm.stories.ts +43 -0
  24. package/stories/login/pages/delete-credential.stories.ts +56 -0
  25. package/stories/login/pages/error.stories.ts +56 -0
  26. package/stories/login/pages/frontchannel-logout.stories.ts +26 -0
  27. package/stories/login/pages/idp-review-user-profile.stories.ts +60 -0
  28. package/stories/login/pages/info.stories.ts +94 -0
  29. package/stories/login/pages/login-config-totp.stories.ts +57 -0
  30. package/stories/login/pages/login-device-verify-user-code.stories.ts +14 -0
  31. package/stories/login/pages/login-idp-link-confirm-override.stories.ts +17 -0
  32. package/stories/login/pages/login-idp-link-confirm.stories.ts +103 -0
  33. package/stories/login/pages/login-idp-link-email.stories.ts +102 -0
  34. package/stories/login/pages/login-oauth-grant.stories.ts +68 -0
  35. package/stories/login/pages/login-oauth2-device-verify-user-code.stories.ts +15 -0
  36. package/stories/login/pages/login-otp.stories.ts +94 -0
  37. package/stories/login/pages/login-page-expired.stories.ts +31 -0
  38. package/stories/login/pages/login-passkeys-conditional-authenticate.stories.ts +16 -0
  39. package/stories/login/pages/login-password.stories.ts +52 -0
  40. package/stories/login/pages/login-recovery-authn-code-config.stories.ts +31 -0
  41. package/stories/login/pages/login-recovery-authn-code-input.stories.ts +16 -0
  42. package/stories/login/pages/login-reset-otp.stories.ts +71 -0
  43. package/stories/login/pages/login-reset-password.stories.ts +50 -0
  44. package/stories/login/pages/login-update-password.stories.ts +46 -0
  45. package/stories/login/pages/login-update-profile.stories.ts +31 -0
  46. package/stories/login/pages/login-username.stories.ts +28 -0
  47. package/stories/login/pages/login-verify-email.stories.ts +98 -0
  48. package/stories/login/pages/login-x509-info.stories.ts +40 -0
  49. package/stories/login/pages/login.stories.ts +260 -0
  50. package/stories/login/pages/logout-confirm.stories.ts +44 -0
  51. package/stories/login/pages/register.stories.ts +230 -0
  52. package/stories/login/pages/saml-post-form.stories.ts +17 -0
  53. package/stories/login/pages/select-authenticator.stories.ts +95 -0
  54. package/stories/login/pages/terms.stories.ts +79 -0
  55. package/stories/login/pages/update-email.stories.ts +31 -0
  56. package/stories/login/pages/webauthn-authenticate.stories.ts +126 -0
  57. package/stories/login/pages/webauthn-error.stories.ts +62 -0
  58. package/stories/login/pages/webauthn-register.stories.ts +46 -0
  59. package/src/bin/tools/runFormat.ts +0 -71
  60. package/src/stories/login/pages/login/login.stories.ts +0 -146
package/bin/main.js CHANGED
@@ -102,6 +102,13 @@ module.exports = require("fs");
102
102
 
103
103
  /***/ }),
104
104
 
105
+ /***/ 943:
106
+ /***/ ((module) => {
107
+
108
+ module.exports = require("fs/promises");
109
+
110
+ /***/ }),
111
+
105
112
  /***/ 161:
106
113
  /***/ ((module) => {
107
114
 
@@ -130,6 +137,13 @@ module.exports = require("path");
130
137
 
131
138
  /***/ }),
132
139
 
140
+ /***/ 824:
141
+ /***/ ((module) => {
142
+
143
+ module.exports = require("prettier");
144
+
145
+ /***/ }),
146
+
133
147
  /***/ 785:
134
148
  /***/ ((module) => {
135
149
 
@@ -319,6 +333,36 @@ const assertIsRefWrapper = {
319
333
  /******/ };
320
334
  /******/ })();
321
335
  /******/
336
+ /******/ /* webpack/runtime/create fake namespace object */
337
+ /******/ (() => {
338
+ /******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
339
+ /******/ var leafPrototypes;
340
+ /******/ // create a fake namespace object
341
+ /******/ // mode & 1: value is a module id, require it
342
+ /******/ // mode & 2: merge all properties of value into the ns
343
+ /******/ // mode & 4: return value when already ns object
344
+ /******/ // mode & 16: return value when it's Promise-like
345
+ /******/ // mode & 8|1: behave like require
346
+ /******/ __nccwpck_require__.t = function(value, mode) {
347
+ /******/ if(mode & 1) value = this(value);
348
+ /******/ if(mode & 8) return value;
349
+ /******/ if(typeof value === 'object' && value) {
350
+ /******/ if((mode & 4) && value.__esModule) return value;
351
+ /******/ if((mode & 16) && typeof value.then === 'function') return value;
352
+ /******/ }
353
+ /******/ var ns = Object.create(null);
354
+ /******/ __nccwpck_require__.r(ns);
355
+ /******/ var def = {};
356
+ /******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
357
+ /******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {
358
+ /******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));
359
+ /******/ }
360
+ /******/ def['default'] = () => (value);
361
+ /******/ __nccwpck_require__.d(ns, def);
362
+ /******/ return ns;
363
+ /******/ };
364
+ /******/ })();
365
+ /******/
322
366
  /******/ /* webpack/runtime/define property getters */
323
367
  /******/ (() => {
324
368
  /******/ // define getter functions for harmony exports
@@ -358,6 +402,17 @@ const assertIsRefWrapper = {
358
402
  /******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
359
403
  /******/ })();
360
404
  /******/
405
+ /******/ /* webpack/runtime/make namespace object */
406
+ /******/ (() => {
407
+ /******/ // define __esModule on exports
408
+ /******/ __nccwpck_require__.r = (exports) => {
409
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
410
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
411
+ /******/ }
412
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
413
+ /******/ };
414
+ /******/ })();
415
+ /******/
361
416
  /******/ /* webpack/runtime/compat */
362
417
  /******/
363
418
  /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
@@ -439,19 +494,19 @@ const { buildContext, commandName } = readParams({ apiVersion: 'v1' });
439
494
  switch (commandName) {
440
495
  case 'add-story':
441
496
  {
442
- console.log("Not yet supported by @keycloakify/angular, we're working on it!");
443
- process.exit(-1);
497
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(402), __nccwpck_require__.e(108)]).then(__nccwpck_require__.bind(__nccwpck_require__, 108));
498
+ command({ buildContext });
444
499
  }
445
500
  return;
446
501
  case 'eject-page':
447
502
  {
448
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(603), __nccwpck_require__.e(925)]).then(__nccwpck_require__.bind(__nccwpck_require__, 925));
503
+ const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(402), __nccwpck_require__.e(84)]).then(__nccwpck_require__.bind(__nccwpck_require__, 84));
449
504
  command({ buildContext });
450
505
  }
451
506
  return;
452
507
  case 'update-kc-gen':
453
508
  {
454
- const { command } = await Promise.all(/* import() */[__nccwpck_require__.e(603), __nccwpck_require__.e(758)]).then(__nccwpck_require__.bind(__nccwpck_require__, 758));
509
+ const { command } = await __nccwpck_require__.e(/* import() */ 758).then(__nccwpck_require__.bind(__nccwpck_require__, 758));
455
510
  command({ buildContext });
456
511
  }
457
512
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keycloakify/angular",
3
- "version": "0.0.11",
3
+ "version": "0.1.0",
4
4
  "peerDependencies": {
5
5
  "keycloakify": "^11.3.16",
6
6
  "@angular/core": "^18.0.0",
@@ -0,0 +1,126 @@
1
+ import { getThisCodebaseRootDirPath } from './tools/getThisCodebaseRootDirPath';
2
+ import cliSelect from 'cli-select';
3
+ import * as fs from 'fs';
4
+ import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from 'path';
5
+ import { assert, Equals } from 'tsafe/assert';
6
+ import chalk from 'chalk';
7
+ import { runPrettier, getIsPrettierAvailable } from './tools/runPrettier';
8
+ import {
9
+ type BuildContext,
10
+ LOGIN_THEME_PAGE_IDS,
11
+ ACCOUNT_THEME_PAGE_IDS,
12
+ type LoginThemePageId,
13
+ type AccountThemePageId,
14
+ THEME_TYPES
15
+ } from './core';
16
+
17
+ export async function command(params: { buildContext: BuildContext }) {
18
+ const { buildContext } = params;
19
+
20
+ console.log(chalk.cyan('Theme type:'));
21
+
22
+ const themeType = await (async () => {
23
+ const values = THEME_TYPES.filter(themeType => {
24
+ switch (themeType) {
25
+ case 'account':
26
+ return buildContext.implementedThemeTypes.account.isImplemented;
27
+ case 'login':
28
+ return buildContext.implementedThemeTypes.login.isImplemented;
29
+ }
30
+ assert<Equals<typeof themeType, never>>(false);
31
+ });
32
+
33
+ assert(values.length > 0, 'No theme is implemented in this project');
34
+
35
+ if (values.length === 1) {
36
+ return values[0];
37
+ }
38
+
39
+ const { value } = await cliSelect({
40
+ values
41
+ }).catch(() => {
42
+ process.exit(-1);
43
+ });
44
+
45
+ return value;
46
+ })();
47
+
48
+ console.log(`→ ${themeType}`);
49
+
50
+ console.log(chalk.cyan('Select the page you want to create a Storybook for:'));
51
+
52
+ const { value: pageId } = await cliSelect<LoginThemePageId | AccountThemePageId>({
53
+ values: (() => {
54
+ switch (themeType) {
55
+ case 'login':
56
+ return [...LOGIN_THEME_PAGE_IDS];
57
+ case 'account':
58
+ return [...ACCOUNT_THEME_PAGE_IDS];
59
+ }
60
+ assert<Equals<typeof themeType, never>>(false);
61
+ })()
62
+ }).catch(() => {
63
+ process.exit(-1);
64
+ });
65
+
66
+ console.log(`→ ${pageId}`);
67
+
68
+ const componentBasename = pageId.replace(/ftl$/, 'stories.ts');
69
+
70
+ const targetFilePath = pathJoin(
71
+ buildContext.themeSrcDirPath,
72
+ themeType,
73
+ 'pages',
74
+ pageId.replace(/\.ftl$/, ''),
75
+ componentBasename
76
+ );
77
+
78
+ if (fs.existsSync(targetFilePath)) {
79
+ console.log(`${pathRelative(process.cwd(), targetFilePath)} already exists`);
80
+
81
+ process.exit(-1);
82
+ }
83
+
84
+ let sourceCode = fs
85
+ .readFileSync(
86
+ pathJoin(
87
+ getThisCodebaseRootDirPath(),
88
+ 'stories',
89
+ themeType,
90
+ 'pages',
91
+ componentBasename
92
+ )
93
+ )
94
+ .toString('utf8')
95
+ .replace(/["']\.\.\/KcPageStory["']/, "'../../KcPageStory'");
96
+
97
+ run_prettier: {
98
+ if (!(await getIsPrettierAvailable())) {
99
+ break run_prettier;
100
+ }
101
+
102
+ sourceCode = await runPrettier({
103
+ filePath: targetFilePath,
104
+ sourceCode: sourceCode
105
+ });
106
+ }
107
+
108
+ {
109
+ const targetDirPath = pathDirname(targetFilePath);
110
+
111
+ if (!fs.existsSync(targetDirPath)) {
112
+ fs.mkdirSync(targetDirPath, { recursive: true });
113
+ }
114
+ }
115
+
116
+ fs.writeFileSync(targetFilePath, Buffer.from(sourceCode, 'utf8'));
117
+
118
+ console.log(
119
+ [
120
+ `${chalk.green('✓')} ${chalk.bold(
121
+ pathJoin('.', pathRelative(process.cwd(), targetFilePath))
122
+ )} copy pasted from the Keycloakify source code into your project`,
123
+ `You can start storybook with ${chalk.bold('npm run storybook')}`
124
+ ].join('\n')
125
+ );
126
+ }
@@ -21,11 +21,11 @@ import {
21
21
  } from 'path';
22
22
  import { assert, Equals } from 'tsafe/assert';
23
23
  import chalk from 'chalk';
24
- import { transformCodebase } from './tools/transformCodebase';
24
+ import { transformCodebase } from './tools/transformCodebase_async';
25
25
  import { kebabCaseToCamelCase } from './tools/kebabCaseToSnakeCase';
26
26
  import { replaceAll } from './tools/String.prototype.replaceAll';
27
27
  import { capitalize } from 'tsafe/capitalize';
28
- import { runFormat } from './tools/runFormat';
28
+ import { getIsPrettierAvailable, runPrettier } from './tools/runPrettier';
29
29
 
30
30
  export async function command(params: { buildContext: BuildContext }) {
31
31
  const { buildContext } = params;
@@ -149,15 +149,33 @@ export async function command(params: { buildContext: BuildContext }) {
149
149
  themeType
150
150
  );
151
151
 
152
- transformCodebase({
152
+ await transformCodebase({
153
153
  srcDirPath: pathJoin(
154
154
  localThemeTypeDirPath,
155
155
  componentDirRelativeToThemeTypePath_i
156
156
  ),
157
157
  destDirPath,
158
- transformSourceCode: ({ filePath, sourceCode }) => {
158
+ transformSourceCode: async ({ filePath, sourceCode }) => {
159
159
  if (!filePath.endsWith('.ts')) {
160
- return { modifiedSourceCode: sourceCode };
160
+ let modifiedSourceCode_str = sourceCode.toString('utf8');
161
+
162
+ run_prettier: {
163
+ if (!(await getIsPrettierAvailable())) {
164
+ break run_prettier;
165
+ }
166
+
167
+ modifiedSourceCode_str = await runPrettier({
168
+ filePath,
169
+ sourceCode: modifiedSourceCode_str
170
+ });
171
+ }
172
+
173
+ return {
174
+ modifiedSourceCode: Buffer.from(
175
+ modifiedSourceCode_str,
176
+ 'utf8'
177
+ )
178
+ };
161
179
  }
162
180
 
163
181
  if (filePath.endsWith('index.ts')) {
@@ -229,6 +247,17 @@ export async function command(params: { buildContext: BuildContext }) {
229
247
  }
230
248
  );
231
249
 
250
+ run_prettier: {
251
+ if (!(await getIsPrettierAvailable())) {
252
+ break run_prettier;
253
+ }
254
+
255
+ modifiedSourceCode_str = await runPrettier({
256
+ filePath,
257
+ sourceCode: modifiedSourceCode_str
258
+ });
259
+ }
260
+
232
261
  return {
233
262
  modifiedSourceCode: Buffer.from(modifiedSourceCode_str, 'utf8')
234
263
  };
@@ -243,10 +272,6 @@ export async function command(params: { buildContext: BuildContext }) {
243
272
  }
244
273
  }
245
274
 
246
- runFormat({
247
- packageJsonFilePath: buildContext.packageJsonFilePath
248
- });
249
-
250
275
  edit_KcPage: {
251
276
  if (
252
277
  pageIdOrComponent !== templateValue &&
@@ -263,17 +288,30 @@ export async function command(params: { buildContext: BuildContext }) {
263
288
 
264
289
  const kcAppTsCode = fs.readFileSync(kcAppTsFilePath).toString('utf8');
265
290
 
266
- const modifiedKcAppTsCode = (() => {
291
+ const modifiedKcAppTsCode = await (async () => {
267
292
  const componentRelativeDirPath_posix = componentDirRelativeToThemeTypePath
268
293
  .split(pathSep)
269
294
  .join('/');
270
295
 
271
- return kcAppTsCode.replace(
296
+ let sourceCode = kcAppTsCode.replace(
272
297
  `@keycloakify/angular/${themeType}/${componentRelativeDirPath_posix}`,
273
298
  componentRelativeDirPath_posix_to_componentRelativeFilePath_posix({
274
299
  componentRelativeDirPath_posix: `./${componentRelativeDirPath_posix}`
275
300
  })
276
301
  );
302
+
303
+ run_prettier: {
304
+ if (!(await getIsPrettierAvailable())) {
305
+ break run_prettier;
306
+ }
307
+
308
+ sourceCode = await runPrettier({
309
+ filePath: kcAppTsFilePath,
310
+ sourceCode
311
+ });
312
+ }
313
+
314
+ return sourceCode;
277
315
  })();
278
316
 
279
317
  if (modifiedKcAppTsCode === kcAppTsCode) {
package/src/bin/main.ts CHANGED
@@ -8,10 +8,8 @@ const { buildContext, commandName } = readParams({ apiVersion: 'v1' });
8
8
  switch (commandName) {
9
9
  case 'add-story':
10
10
  {
11
- console.log(
12
- "Not yet supported by @keycloakify/angular, we're working on it!"
13
- );
14
- process.exit(-1);
11
+ const { command } = await import('./add-story');
12
+ command({ buildContext });
15
13
  }
16
14
  return;
17
15
  case 'eject-page':
@@ -0,0 +1,38 @@
1
+ import { sep as pathSep } from 'path';
2
+
3
+ let cache: string | undefined = undefined;
4
+
5
+ export function getNodeModulesBinDirPath() {
6
+ if (cache !== undefined) {
7
+ return cache;
8
+ }
9
+
10
+ const binPath = process.argv[1];
11
+
12
+ const segments: string[] = ['.bin'];
13
+
14
+ let foundNodeModules = false;
15
+
16
+ for (const segment of binPath.split(pathSep).reverse()) {
17
+ skip_segment: {
18
+ if (foundNodeModules) {
19
+ break skip_segment;
20
+ }
21
+
22
+ if (segment === 'node_modules') {
23
+ foundNodeModules = true;
24
+ break skip_segment;
25
+ }
26
+
27
+ continue;
28
+ }
29
+
30
+ segments.unshift(segment);
31
+ }
32
+
33
+ const nodeModulesBinDirPath = segments.join(pathSep);
34
+
35
+ cache = nodeModulesBinDirPath;
36
+
37
+ return nodeModulesBinDirPath;
38
+ }
@@ -0,0 +1,89 @@
1
+ import { getNodeModulesBinDirPath } from './nodeModulesBinDirPath';
2
+ import { join as pathJoin } from 'path';
3
+ import * as fsPr from 'fs/promises';
4
+ import { id } from 'tsafe/id';
5
+ import { assert } from 'tsafe/assert';
6
+ import chalk from 'chalk';
7
+
8
+ getIsPrettierAvailable.cache = id<boolean | undefined>(undefined);
9
+
10
+ export async function getIsPrettierAvailable(): Promise<boolean> {
11
+ if (getIsPrettierAvailable.cache !== undefined) {
12
+ return getIsPrettierAvailable.cache;
13
+ }
14
+
15
+ const nodeModulesBinDirPath = getNodeModulesBinDirPath();
16
+
17
+ const prettierBinPath = pathJoin(nodeModulesBinDirPath, 'prettier');
18
+
19
+ const stats = await fsPr.stat(prettierBinPath).catch(() => undefined);
20
+
21
+ const isPrettierAvailable = stats?.isFile() ?? false;
22
+
23
+ getIsPrettierAvailable.cache = isPrettierAvailable;
24
+
25
+ return isPrettierAvailable;
26
+ }
27
+
28
+ type PrettierAndConfig = {
29
+ prettier: typeof import('prettier');
30
+ config: import('prettier').Options | null;
31
+ };
32
+
33
+ getPrettierAndConfig.cache = id<PrettierAndConfig | undefined>(undefined);
34
+
35
+ export async function getPrettierAndConfig(): Promise<PrettierAndConfig> {
36
+ assert(getIsPrettierAvailable());
37
+
38
+ if (getPrettierAndConfig.cache !== undefined) {
39
+ return getPrettierAndConfig.cache;
40
+ }
41
+
42
+ const prettier = await import('prettier');
43
+
44
+ const prettierAndConfig: PrettierAndConfig = {
45
+ prettier,
46
+ config: await prettier.resolveConfig(pathJoin(getNodeModulesBinDirPath(), '..'))
47
+ };
48
+
49
+ getPrettierAndConfig.cache = prettierAndConfig;
50
+
51
+ return prettierAndConfig;
52
+ }
53
+
54
+ export async function runPrettier(params: {
55
+ sourceCode: string;
56
+ filePath: string;
57
+ }): Promise<string> {
58
+ const { sourceCode, filePath } = params;
59
+
60
+ let formattedSourceCode: string;
61
+
62
+ try {
63
+ const { prettier, config } = await getPrettierAndConfig();
64
+
65
+ const { ignored, inferredParser } = await prettier.getFileInfo(filePath, {
66
+ resolveConfig: true
67
+ });
68
+
69
+ if (ignored) {
70
+ return sourceCode;
71
+ }
72
+
73
+ formattedSourceCode = await prettier.format(sourceCode, {
74
+ ...config,
75
+ filePath,
76
+ parser: inferredParser ?? undefined
77
+ });
78
+ } catch (error) {
79
+ console.log(
80
+ chalk.red(
81
+ `You probably need to upgrade the version of prettier in your project`
82
+ )
83
+ );
84
+
85
+ throw error;
86
+ }
87
+
88
+ return formattedSourceCode;
89
+ }
@@ -0,0 +1,89 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { crawl } from './crawl';
4
+ import { rmSync } from '../tools/fs.rmSync';
5
+
6
+ type TransformSourceCode = (params: {
7
+ sourceCode: Buffer;
8
+ filePath: string;
9
+ fileRelativePath: string;
10
+ }) => Promise<
11
+ | {
12
+ modifiedSourceCode: Buffer;
13
+ newFileName?: string;
14
+ }
15
+ | undefined
16
+ >;
17
+
18
+ /**
19
+ * Apply a transformation function to every file of directory
20
+ * If source and destination are the same this function can be used to apply the transformation in place
21
+ * like filtering out some files or modifying them.
22
+ * */
23
+ export async function transformCodebase(params: {
24
+ srcDirPath: string;
25
+ destDirPath: string;
26
+ transformSourceCode?: TransformSourceCode;
27
+ }) {
28
+ const { srcDirPath, transformSourceCode } = params;
29
+
30
+ const isTargetSameAsSource = path.relative(srcDirPath, params.destDirPath) === '';
31
+
32
+ const destDirPath = isTargetSameAsSource
33
+ ? path.join(srcDirPath, '..', 'tmp_xOsPdkPsTdzPs34sOkHs')
34
+ : params.destDirPath;
35
+
36
+ fs.mkdirSync(destDirPath, {
37
+ recursive: true
38
+ });
39
+
40
+ for (const fileRelativePath of crawl({
41
+ dirPath: srcDirPath,
42
+ returnedPathsType: 'relative to dirPath'
43
+ })) {
44
+ const filePath = path.join(srcDirPath, fileRelativePath);
45
+ const destFilePath = path.join(destDirPath, fileRelativePath);
46
+
47
+ // NOTE: Optimization, if we don't need to transform the file, just copy
48
+ // it using the lower level implementation.
49
+ if (transformSourceCode === undefined) {
50
+ fs.mkdirSync(path.dirname(destFilePath), {
51
+ recursive: true
52
+ });
53
+
54
+ fs.copyFileSync(filePath, destFilePath);
55
+
56
+ continue;
57
+ }
58
+
59
+ const transformSourceCodeResult = await transformSourceCode({
60
+ sourceCode: fs.readFileSync(filePath),
61
+ filePath,
62
+ fileRelativePath
63
+ });
64
+
65
+ if (transformSourceCodeResult === undefined) {
66
+ continue;
67
+ }
68
+
69
+ fs.mkdirSync(path.dirname(destFilePath), {
70
+ recursive: true
71
+ });
72
+
73
+ const { newFileName, modifiedSourceCode } = transformSourceCodeResult;
74
+
75
+ fs.writeFileSync(
76
+ path.join(
77
+ path.dirname(destFilePath),
78
+ newFileName ?? path.basename(destFilePath)
79
+ ),
80
+ modifiedSourceCode
81
+ );
82
+ }
83
+
84
+ if (isTargetSameAsSource) {
85
+ rmSync(srcDirPath, { recursive: true });
86
+
87
+ fs.renameSync(destDirPath, srcDirPath);
88
+ }
89
+ }
@@ -1,10 +1,10 @@
1
1
  import type { BuildContext } from './core';
2
2
  import * as fs from 'fs';
3
3
  import { join as pathJoin } from 'path';
4
- import { runFormat } from './tools/runFormat';
4
+ import { getIsPrettierAvailable, runPrettier } from './tools/runPrettier';
5
5
  import * as crypto from 'crypto';
6
6
 
7
- export function command(params: { buildContext: BuildContext }) {
7
+ export async function command(params: { buildContext: BuildContext }) {
8
8
  const { buildContext } = params;
9
9
 
10
10
  const filePath = pathJoin(buildContext.themeSrcDirPath, 'kc.gen.ts');
@@ -149,18 +149,23 @@ export function command(params: { buildContext: BuildContext }) {
149
149
  return;
150
150
  }
151
151
 
152
- fs.writeFileSync(
153
- filePath,
154
- Buffer.from(
155
- [
156
- `// This file is auto-generated by keycloakify. Do not edit it manually.`,
157
- `// Hash: ${hash}`,
158
- ``,
159
- newContent
160
- ].join('\n'),
161
- 'utf8'
162
- )
163
- );
152
+ let sourceCode = [
153
+ `// This file is auto-generated by keycloakify. Do not edit it manually.`,
154
+ `// Hash: ${hash}`,
155
+ ``,
156
+ newContent
157
+ ].join('\n');
158
+
159
+ run_prettier: {
160
+ if (!(await getIsPrettierAvailable())) {
161
+ break run_prettier;
162
+ }
163
+
164
+ sourceCode = await runPrettier({
165
+ filePath,
166
+ sourceCode
167
+ });
168
+ }
164
169
 
165
- runFormat({ packageJsonFilePath: buildContext.packageJsonFilePath });
170
+ fs.writeFileSync(filePath, Buffer.from(sourceCode, 'utf8'));
166
171
  }