keycloakify 11.6.1 → 11.6.2
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/bin/363.index.js +1528 -0
- package/bin/453.index.js +1 -1
- package/bin/735.index.js +1 -1
- package/bin/{615.index.js → 840.index.js} +9 -9
- package/bin/930.index.js +165 -0
- package/bin/946.index.js +20 -0
- package/bin/main.js +58 -16
- package/bin/{eject-file.d.ts → own.d.ts} +2 -1
- package/bin/shared/{addPostinstallScriptIfNotPresent.d.ts → addSyncExtensionsToPostinstallScript.d.ts} +1 -1
- package/bin/{postinstall/uiModuleMeta.d.ts → sync-extensions/extensionModuleMeta.d.ts} +5 -5
- package/bin/sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.d.ts +12 -0
- package/bin/sync-extensions/index.d.ts +1 -0
- package/bin/{postinstall/installUiModulesPeerDependencies.d.ts → sync-extensions/installExtensionModulesPeerDependencies.d.ts} +3 -3
- package/bin/{postinstall → sync-extensions}/managedGitignoreFile.d.ts +4 -4
- package/bin/tools/isKnownByGit.d.ts +3 -0
- package/package.json +23 -23
- package/src/bin/eject-page.ts +1 -3
- package/src/bin/initialize-admin-theme.ts +2 -2
- package/src/bin/main.ts +61 -16
- package/src/bin/own.ts +209 -0
- package/src/bin/shared/{addPostinstallScriptIfNotPresent.ts → addSyncExtensionsToPostinstallScript.ts} +2 -2
- package/src/bin/{postinstall/uiModuleMeta.ts → sync-extensions/extensionModuleMeta.ts} +48 -42
- package/src/bin/{postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts → sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.ts} +32 -21
- package/src/bin/sync-extensions/index.ts +1 -0
- package/src/bin/{postinstall/installUiModulesPeerDependencies.ts → sync-extensions/installExtensionModulesPeerDependencies.ts} +15 -13
- package/src/bin/{postinstall → sync-extensions}/managedGitignoreFile.ts +18 -18
- package/src/bin/{postinstall/postinstall.ts → sync-extensions/sync-extension.ts} +14 -26
- package/src/bin/tools/isKnownByGit.ts +45 -0
- package/src/bin/tools/listInstalledModules.ts +2 -2
- package/src/bin/tools/npmInstall.ts +1 -1
- package/src/bin/tools/untrackFromGit.ts +19 -3
- package/bin/300.index.js +0 -770
- package/bin/653.index.js +0 -753
- package/bin/854.index.js +0 -68
- package/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.d.ts +0 -12
- package/bin/postinstall/index.d.ts +0 -1
- package/bin/tools/isTrackedByGit.d.ts +0 -3
- package/src/bin/eject-file.ts +0 -68
- package/src/bin/postinstall/index.ts +0 -1
- package/src/bin/tools/isTrackedByGit.ts +0 -29
- /package/bin/{postinstall/postinstall.d.ts → sync-extensions/sync-extension.d.ts} +0 -0
package/src/bin/main.ts
CHANGED
@@ -248,13 +248,30 @@ program
|
|
248
248
|
|
249
249
|
program
|
250
250
|
.command({
|
251
|
-
name: "
|
252
|
-
description:
|
251
|
+
name: "sync-extensions",
|
252
|
+
description: [
|
253
|
+
"Synchronizes all installed Keycloakify extension modules with your project.",
|
254
|
+
"",
|
255
|
+
"Example of extension modules: '@keycloakify/keycloak-account-ui', '@keycloakify/keycloak-admin-ui', '@keycloakify/keycloak-ui-shared'",
|
256
|
+
"",
|
257
|
+
"This command ensures that:",
|
258
|
+
"- All required files from installed extensions are copied into your project.",
|
259
|
+
"- The copied files are correctly ignored by Git to help you distinguish between your custom source files",
|
260
|
+
" and those provided by the extensions.",
|
261
|
+
"- Peer dependencies declared by the extensions are automatically added to your package.json.",
|
262
|
+
"",
|
263
|
+
"You can safely run this command multiple times. It will only update the files and dependencies if needed,",
|
264
|
+
"ensuring your project stays in sync with the installed extensions.",
|
265
|
+
"",
|
266
|
+
"Typical usage:",
|
267
|
+
"- Should be run as a postinstall script of your project.",
|
268
|
+
""
|
269
|
+
].join("\n")
|
253
270
|
})
|
254
271
|
.task({
|
255
272
|
skip,
|
256
273
|
handler: async ({ projectDirPath }) => {
|
257
|
-
const { command } = await import("./
|
274
|
+
const { command } = await import("./sync-extensions");
|
258
275
|
|
259
276
|
await command({ buildContext: getBuildContext({ projectDirPath }) });
|
260
277
|
}
|
@@ -262,37 +279,65 @@ program
|
|
262
279
|
|
263
280
|
program
|
264
281
|
.command<{
|
265
|
-
|
282
|
+
path: string;
|
283
|
+
revert: boolean;
|
266
284
|
}>({
|
267
|
-
name: "
|
285
|
+
name: "own",
|
268
286
|
description: [
|
269
|
-
"
|
270
|
-
"
|
271
|
-
|
287
|
+
"Manages ownership of auto-generated files provided by Keycloakify extensions.",
|
288
|
+
"",
|
289
|
+
"This command allows you to take ownership of a specific file or directory generated",
|
290
|
+
"by an extension. Once owned, you can freely modify and version-control the file.",
|
291
|
+
"",
|
292
|
+
"You can also use the --revert flag to relinquish ownership and restore the file",
|
293
|
+
"or directory to its original auto-generated state.",
|
294
|
+
"",
|
295
|
+
"For convenience, the exact command to take ownership of any file is included as a comment",
|
296
|
+
"in the header of each extension-generated file.",
|
297
|
+
"",
|
298
|
+
"Examples:",
|
299
|
+
"$ npx keycloakify own --path admin/KcPage.tsx"
|
300
|
+
].join("\n")
|
272
301
|
})
|
273
302
|
.option({
|
274
|
-
key: "
|
303
|
+
key: "path",
|
275
304
|
name: (() => {
|
276
|
-
const long = "
|
277
|
-
const short = "
|
305
|
+
const long = "path";
|
306
|
+
const short = "p";
|
278
307
|
|
279
308
|
optionsKeys.push(long, short);
|
280
309
|
|
281
310
|
return { long, short };
|
282
311
|
})(),
|
283
312
|
description: [
|
284
|
-
"
|
285
|
-
"
|
313
|
+
"Specifies the relative path of the file or directory to take ownership of.",
|
314
|
+
"This path should be relative to your theme directory.",
|
315
|
+
"Example: `--path 'admin/KcPage.tsx'`"
|
286
316
|
].join(" ")
|
287
317
|
})
|
318
|
+
.option({
|
319
|
+
key: "revert",
|
320
|
+
name: (() => {
|
321
|
+
const name = "revert";
|
322
|
+
|
323
|
+
optionsKeys.push(name);
|
324
|
+
|
325
|
+
return name;
|
326
|
+
})(),
|
327
|
+
description: [
|
328
|
+
"Restores a file or directory to its original auto-generated state,",
|
329
|
+
"removing your ownership claim and reverting any modifications."
|
330
|
+
].join(" "),
|
331
|
+
defaultValue: false
|
332
|
+
})
|
288
333
|
.task({
|
289
334
|
skip,
|
290
|
-
handler: async ({ projectDirPath,
|
291
|
-
const { command } = await import("./
|
335
|
+
handler: async ({ projectDirPath, path, revert }) => {
|
336
|
+
const { command } = await import("./own");
|
292
337
|
|
293
338
|
await command({
|
294
339
|
buildContext: getBuildContext({ projectDirPath }),
|
295
|
-
cliCommandOptions: {
|
340
|
+
cliCommandOptions: { path, isRevert: revert }
|
296
341
|
});
|
297
342
|
}
|
298
343
|
});
|
package/src/bin/own.ts
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
import type { BuildContext } from "./shared/buildContext";
|
2
|
+
import { getExtensionModuleFileSourceCodeReadyToBeCopied } from "./sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied";
|
3
|
+
import type { ExtensionModuleMeta } from "./sync-extensions/extensionModuleMeta";
|
4
|
+
import { command as command_syncExtensions } from "./sync-extensions/sync-extension";
|
5
|
+
import {
|
6
|
+
readManagedGitignoreFile,
|
7
|
+
writeManagedGitignoreFile
|
8
|
+
} from "./sync-extensions/managedGitignoreFile";
|
9
|
+
import { getExtensionModuleMetas } from "./sync-extensions/extensionModuleMeta";
|
10
|
+
import { getAbsoluteAndInOsFormatPath } from "./tools/getAbsoluteAndInOsFormatPath";
|
11
|
+
import { relative as pathRelative, dirname as pathDirname, join as pathJoin } from "path";
|
12
|
+
import { getInstalledModuleDirPath } from "./tools/getInstalledModuleDirPath";
|
13
|
+
import * as fsPr from "fs/promises";
|
14
|
+
import { isInside } from "./tools/isInside";
|
15
|
+
import chalk from "chalk";
|
16
|
+
|
17
|
+
export async function command(params: {
|
18
|
+
buildContext: BuildContext;
|
19
|
+
cliCommandOptions: {
|
20
|
+
path: string;
|
21
|
+
isRevert: boolean;
|
22
|
+
};
|
23
|
+
}) {
|
24
|
+
const { buildContext, cliCommandOptions } = params;
|
25
|
+
|
26
|
+
const extensionModuleMetas = await getExtensionModuleMetas({ buildContext });
|
27
|
+
|
28
|
+
const { targetFileRelativePathsByExtensionModuleMeta } = await (async () => {
|
29
|
+
const fileOrDirectoryRelativePath = pathRelative(
|
30
|
+
buildContext.themeSrcDirPath,
|
31
|
+
getAbsoluteAndInOsFormatPath({
|
32
|
+
cwd: buildContext.themeSrcDirPath,
|
33
|
+
pathIsh: cliCommandOptions.path
|
34
|
+
})
|
35
|
+
);
|
36
|
+
|
37
|
+
const arr = extensionModuleMetas
|
38
|
+
.map(extensionModuleMeta => ({
|
39
|
+
extensionModuleMeta,
|
40
|
+
fileRelativePaths: extensionModuleMeta.files
|
41
|
+
.map(({ fileRelativePath }) => fileRelativePath)
|
42
|
+
.filter(
|
43
|
+
fileRelativePath =>
|
44
|
+
fileRelativePath === fileOrDirectoryRelativePath ||
|
45
|
+
isInside({
|
46
|
+
dirPath: fileOrDirectoryRelativePath,
|
47
|
+
filePath: fileRelativePath
|
48
|
+
})
|
49
|
+
)
|
50
|
+
}))
|
51
|
+
.filter(({ fileRelativePaths }) => fileRelativePaths.length !== 0);
|
52
|
+
|
53
|
+
const targetFileRelativePathsByExtensionModuleMeta = new Map<
|
54
|
+
ExtensionModuleMeta,
|
55
|
+
string[]
|
56
|
+
>();
|
57
|
+
|
58
|
+
for (const { extensionModuleMeta, fileRelativePaths } of arr) {
|
59
|
+
targetFileRelativePathsByExtensionModuleMeta.set(
|
60
|
+
extensionModuleMeta,
|
61
|
+
fileRelativePaths
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
return { targetFileRelativePathsByExtensionModuleMeta };
|
66
|
+
})();
|
67
|
+
|
68
|
+
if (targetFileRelativePathsByExtensionModuleMeta.size === 0) {
|
69
|
+
console.log(
|
70
|
+
chalk.yellow(
|
71
|
+
"There is no Keycloakify extension modules files matching the provided path."
|
72
|
+
)
|
73
|
+
);
|
74
|
+
process.exit(1);
|
75
|
+
}
|
76
|
+
|
77
|
+
const { ownedFilesRelativePaths: ownedFilesRelativePaths_current } =
|
78
|
+
await readManagedGitignoreFile({
|
79
|
+
buildContext
|
80
|
+
});
|
81
|
+
|
82
|
+
await (cliCommandOptions.isRevert ? command_revert : command_own)({
|
83
|
+
extensionModuleMetas,
|
84
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
85
|
+
ownedFilesRelativePaths_current,
|
86
|
+
buildContext
|
87
|
+
});
|
88
|
+
}
|
89
|
+
|
90
|
+
type Params_subcommands = {
|
91
|
+
extensionModuleMetas: ExtensionModuleMeta[];
|
92
|
+
targetFileRelativePathsByExtensionModuleMeta: Map<ExtensionModuleMeta, string[]>;
|
93
|
+
ownedFilesRelativePaths_current: string[];
|
94
|
+
buildContext: BuildContext;
|
95
|
+
};
|
96
|
+
|
97
|
+
async function command_own(params: Params_subcommands) {
|
98
|
+
const {
|
99
|
+
extensionModuleMetas,
|
100
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
101
|
+
ownedFilesRelativePaths_current,
|
102
|
+
buildContext
|
103
|
+
} = params;
|
104
|
+
|
105
|
+
await writeManagedGitignoreFile({
|
106
|
+
buildContext,
|
107
|
+
extensionModuleMetas,
|
108
|
+
ownedFilesRelativePaths: [
|
109
|
+
...ownedFilesRelativePaths_current,
|
110
|
+
...Array.from(targetFileRelativePathsByExtensionModuleMeta.values())
|
111
|
+
.flat()
|
112
|
+
.filter(
|
113
|
+
fileRelativePath =>
|
114
|
+
!ownedFilesRelativePaths_current.includes(fileRelativePath)
|
115
|
+
)
|
116
|
+
]
|
117
|
+
});
|
118
|
+
|
119
|
+
const writeActions: (() => Promise<void>)[] = [];
|
120
|
+
|
121
|
+
for (const [
|
122
|
+
extensionModuleMeta,
|
123
|
+
fileRelativePaths
|
124
|
+
] of targetFileRelativePathsByExtensionModuleMeta.entries()) {
|
125
|
+
const extensionModuleDirPath = await getInstalledModuleDirPath({
|
126
|
+
moduleName: extensionModuleMeta.moduleName,
|
127
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath),
|
128
|
+
projectDirPath: buildContext.projectDirPath
|
129
|
+
});
|
130
|
+
|
131
|
+
for (const fileRelativePath of fileRelativePaths) {
|
132
|
+
if (ownedFilesRelativePaths_current.includes(fileRelativePath)) {
|
133
|
+
console.log(
|
134
|
+
chalk.grey(`You already have ownership over '${fileRelativePath}'.`)
|
135
|
+
);
|
136
|
+
continue;
|
137
|
+
}
|
138
|
+
|
139
|
+
writeActions.push(async () => {
|
140
|
+
const sourceCode = await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
141
|
+
buildContext,
|
142
|
+
fileRelativePath,
|
143
|
+
isOwnershipAction: true,
|
144
|
+
extensionModuleName: extensionModuleMeta.moduleName,
|
145
|
+
extensionModuleDirPath,
|
146
|
+
extensionModuleVersion: extensionModuleMeta.version
|
147
|
+
});
|
148
|
+
|
149
|
+
await fsPr.writeFile(
|
150
|
+
pathJoin(buildContext.themeSrcDirPath, fileRelativePath),
|
151
|
+
sourceCode
|
152
|
+
);
|
153
|
+
|
154
|
+
console.log(chalk.green(`Ownership over '${fileRelativePath}' claimed.`));
|
155
|
+
});
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
if (writeActions.length === 0) {
|
160
|
+
console.log(chalk.yellow("No new file claimed."));
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
|
164
|
+
await Promise.all(writeActions.map(action => action()));
|
165
|
+
}
|
166
|
+
|
167
|
+
async function command_revert(params: Params_subcommands) {
|
168
|
+
const {
|
169
|
+
extensionModuleMetas,
|
170
|
+
targetFileRelativePathsByExtensionModuleMeta,
|
171
|
+
ownedFilesRelativePaths_current,
|
172
|
+
buildContext
|
173
|
+
} = params;
|
174
|
+
|
175
|
+
const ownedFilesRelativePaths_toRemove = Array.from(
|
176
|
+
targetFileRelativePathsByExtensionModuleMeta.values()
|
177
|
+
)
|
178
|
+
.flat()
|
179
|
+
.filter(fileRelativePath => {
|
180
|
+
if (!ownedFilesRelativePaths_current.includes(fileRelativePath)) {
|
181
|
+
console.log(
|
182
|
+
chalk.grey(`Ownership over '${fileRelativePath}' wasn't claimed.`)
|
183
|
+
);
|
184
|
+
return false;
|
185
|
+
}
|
186
|
+
|
187
|
+
console.log(
|
188
|
+
chalk.green(`Ownership over '${fileRelativePath}' relinquished.`)
|
189
|
+
);
|
190
|
+
|
191
|
+
return true;
|
192
|
+
});
|
193
|
+
|
194
|
+
if (ownedFilesRelativePaths_toRemove.length === 0) {
|
195
|
+
console.log(chalk.yellow("No file relinquished."));
|
196
|
+
return;
|
197
|
+
}
|
198
|
+
|
199
|
+
await writeManagedGitignoreFile({
|
200
|
+
buildContext,
|
201
|
+
extensionModuleMetas,
|
202
|
+
ownedFilesRelativePaths: ownedFilesRelativePaths_current.filter(
|
203
|
+
fileRelativePath =>
|
204
|
+
!ownedFilesRelativePaths_toRemove.includes(fileRelativePath)
|
205
|
+
)
|
206
|
+
});
|
207
|
+
|
208
|
+
await command_syncExtensions({ buildContext });
|
209
|
+
}
|
@@ -9,13 +9,13 @@ export type BuildContextLike = {
|
|
9
9
|
|
10
10
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
11
11
|
|
12
|
-
export function
|
12
|
+
export function addSyncExtensionsToPostinstallScript(params: {
|
13
13
|
parsedPackageJson: { scripts?: Record<string, string | undefined> };
|
14
14
|
buildContext: BuildContextLike;
|
15
15
|
}) {
|
16
16
|
const { parsedPackageJson, buildContext } = params;
|
17
17
|
|
18
|
-
const cmd_base = "keycloakify
|
18
|
+
const cmd_base = "keycloakify sync-extensions";
|
19
19
|
|
20
20
|
const projectCliOptionValue = (() => {
|
21
21
|
const packageJsonDirPath = pathDirname(buildContext.packageJsonFilePath);
|
@@ -10,15 +10,15 @@ import { crawlAsync } from "../tools/crawlAsync";
|
|
10
10
|
import { getIsPrettierAvailable, getPrettier } from "../tools/runPrettier";
|
11
11
|
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
12
12
|
import {
|
13
|
-
|
14
|
-
type BuildContextLike as
|
15
|
-
} from "./
|
13
|
+
getExtensionModuleFileSourceCodeReadyToBeCopied,
|
14
|
+
type BuildContextLike as BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied
|
15
|
+
} from "./getExtensionModuleFileSourceCodeReadyToBeCopied";
|
16
16
|
import * as crypto from "crypto";
|
17
17
|
import { KEYCLOAK_THEME } from "../shared/constants";
|
18
18
|
import { exclude } from "tsafe/exclude";
|
19
19
|
import { isAmong } from "tsafe/isAmong";
|
20
20
|
|
21
|
-
export type
|
21
|
+
export type ExtensionModuleMeta = {
|
22
22
|
moduleName: string;
|
23
23
|
version: string;
|
24
24
|
files: {
|
@@ -29,8 +29,8 @@ export type UiModuleMeta = {
|
|
29
29
|
peerDependencies: Record<string, string>;
|
30
30
|
};
|
31
31
|
|
32
|
-
const
|
33
|
-
type ExpectedType =
|
32
|
+
const zExtensionModuleMeta = (() => {
|
33
|
+
type ExpectedType = ExtensionModuleMeta;
|
34
34
|
|
35
35
|
const zTargetType = z.object({
|
36
36
|
moduleName: z.string(),
|
@@ -56,7 +56,7 @@ type ParsedCacheFile = {
|
|
56
56
|
keycloakifyVersion: string;
|
57
57
|
prettierConfigHash: string | null;
|
58
58
|
thisFilePath: string;
|
59
|
-
|
59
|
+
extensionModuleMetas: ExtensionModuleMeta[];
|
60
60
|
};
|
61
61
|
|
62
62
|
const zParsedCacheFile = (() => {
|
@@ -66,7 +66,7 @@ const zParsedCacheFile = (() => {
|
|
66
66
|
keycloakifyVersion: z.string(),
|
67
67
|
prettierConfigHash: z.union([z.string(), z.null()]),
|
68
68
|
thisFilePath: z.string(),
|
69
|
-
|
69
|
+
extensionModuleMetas: z.array(zExtensionModuleMeta)
|
70
70
|
});
|
71
71
|
|
72
72
|
type InferredType = z.infer<typeof zTargetType>;
|
@@ -76,10 +76,10 @@ const zParsedCacheFile = (() => {
|
|
76
76
|
return id<z.ZodType<ExpectedType>>(zTargetType);
|
77
77
|
})();
|
78
78
|
|
79
|
-
const CACHE_FILE_RELATIVE_PATH = pathJoin("
|
79
|
+
const CACHE_FILE_RELATIVE_PATH = pathJoin("extension-modules", "cache.json");
|
80
80
|
|
81
81
|
export type BuildContextLike =
|
82
|
-
|
82
|
+
BuildContextLike_getExtensionModuleFileSourceCodeReadyToBeCopied & {
|
83
83
|
cacheDirPath: string;
|
84
84
|
packageJsonFilePath: string;
|
85
85
|
projectDirPath: string;
|
@@ -87,9 +87,9 @@ export type BuildContextLike =
|
|
87
87
|
|
88
88
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
89
89
|
|
90
|
-
export async function
|
90
|
+
export async function getExtensionModuleMetas(params: {
|
91
91
|
buildContext: BuildContextLike;
|
92
|
-
}): Promise<
|
92
|
+
}): Promise<ExtensionModuleMeta[]> {
|
93
93
|
const { buildContext } = params;
|
94
94
|
|
95
95
|
const cacheFilePath = pathJoin(buildContext.cacheDirPath, CACHE_FILE_RELATIVE_PATH);
|
@@ -106,7 +106,7 @@ export async function getUiModuleMetas(params: {
|
|
106
106
|
return configHash;
|
107
107
|
})();
|
108
108
|
|
109
|
-
const
|
109
|
+
const installedExtensionModules = await (async () => {
|
110
110
|
const installedModulesWithKeycloakifyInTheName = await listInstalledModules({
|
111
111
|
packageJsonFilePath: buildContext.packageJsonFilePath,
|
112
112
|
projectDirPath: buildContext.packageJsonFilePath,
|
@@ -134,7 +134,7 @@ export async function getUiModuleMetas(params: {
|
|
134
134
|
return await fsPr.readFile(cacheFilePath);
|
135
135
|
})();
|
136
136
|
|
137
|
-
const
|
137
|
+
const extensionModuleMetas_cacheUpToDate: ExtensionModuleMeta[] = await (async () => {
|
138
138
|
const parsedCacheFile: ParsedCacheFile | undefined = await (async () => {
|
139
139
|
if (cacheContent === undefined) {
|
140
140
|
return undefined;
|
@@ -177,45 +177,51 @@ export async function getUiModuleMetas(params: {
|
|
177
177
|
return [];
|
178
178
|
}
|
179
179
|
|
180
|
-
const
|
181
|
-
|
182
|
-
const
|
183
|
-
|
184
|
-
|
185
|
-
|
180
|
+
const extensionModuleMetas_cacheUpToDate =
|
181
|
+
parsedCacheFile.extensionModuleMetas.filter(extensionModuleMeta => {
|
182
|
+
const correspondingInstalledExtensionModule =
|
183
|
+
installedExtensionModules.find(
|
184
|
+
installedExtensionModule =>
|
185
|
+
installedExtensionModule.moduleName ===
|
186
|
+
extensionModuleMeta.moduleName
|
187
|
+
);
|
186
188
|
|
187
|
-
if (
|
189
|
+
if (correspondingInstalledExtensionModule === undefined) {
|
188
190
|
return false;
|
189
191
|
}
|
190
192
|
|
191
|
-
return
|
192
|
-
|
193
|
-
|
193
|
+
return (
|
194
|
+
correspondingInstalledExtensionModule.version ===
|
195
|
+
extensionModuleMeta.version
|
196
|
+
);
|
197
|
+
});
|
194
198
|
|
195
|
-
return
|
199
|
+
return extensionModuleMetas_cacheUpToDate;
|
196
200
|
})();
|
197
201
|
|
198
|
-
const
|
199
|
-
|
202
|
+
const extensionModuleMetas = await Promise.all(
|
203
|
+
installedExtensionModules.map(
|
200
204
|
async ({
|
201
205
|
moduleName,
|
202
206
|
version,
|
203
207
|
peerDependencies,
|
204
208
|
dirPath
|
205
|
-
}): Promise<
|
209
|
+
}): Promise<ExtensionModuleMeta> => {
|
206
210
|
use_cache: {
|
207
|
-
const
|
208
|
-
|
209
|
-
|
211
|
+
const extensionModuleMeta_cache =
|
212
|
+
extensionModuleMetas_cacheUpToDate.find(
|
213
|
+
extensionModuleMeta =>
|
214
|
+
extensionModuleMeta.moduleName === moduleName
|
215
|
+
);
|
210
216
|
|
211
|
-
if (
|
217
|
+
if (extensionModuleMeta_cache === undefined) {
|
212
218
|
break use_cache;
|
213
219
|
}
|
214
220
|
|
215
|
-
return
|
221
|
+
return extensionModuleMeta_cache;
|
216
222
|
}
|
217
223
|
|
218
|
-
const files:
|
224
|
+
const files: ExtensionModuleMeta["files"] = [];
|
219
225
|
|
220
226
|
{
|
221
227
|
const srcDirPath = pathJoin(dirPath, KEYCLOAK_THEME);
|
@@ -225,13 +231,13 @@ export async function getUiModuleMetas(params: {
|
|
225
231
|
returnedPathsType: "relative to dirPath",
|
226
232
|
onFileFound: async fileRelativePath => {
|
227
233
|
const sourceCode =
|
228
|
-
await
|
234
|
+
await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
229
235
|
buildContext,
|
230
236
|
fileRelativePath,
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
237
|
+
isOwnershipAction: false,
|
238
|
+
extensionModuleDirPath: dirPath,
|
239
|
+
extensionModuleName: moduleName,
|
240
|
+
extensionModuleVersion: version
|
235
241
|
});
|
236
242
|
|
237
243
|
const hash = computeHash(sourceCode);
|
@@ -261,7 +267,7 @@ export async function getUiModuleMetas(params: {
|
|
261
267
|
});
|
262
268
|
}
|
263
269
|
|
264
|
-
return id<
|
270
|
+
return id<ExtensionModuleMeta>({
|
265
271
|
moduleName,
|
266
272
|
version,
|
267
273
|
files,
|
@@ -281,7 +287,7 @@ export async function getUiModuleMetas(params: {
|
|
281
287
|
keycloakifyVersion,
|
282
288
|
prettierConfigHash,
|
283
289
|
thisFilePath: cacheFilePath,
|
284
|
-
|
290
|
+
extensionModuleMetas
|
285
291
|
});
|
286
292
|
|
287
293
|
const cacheContent_new = Buffer.from(
|
@@ -306,7 +312,7 @@ export async function getUiModuleMetas(params: {
|
|
306
312
|
await fsPr.writeFile(cacheFilePath, cacheContent_new);
|
307
313
|
}
|
308
314
|
|
309
|
-
return
|
315
|
+
return extensionModuleMetas;
|
310
316
|
}
|
311
317
|
|
312
318
|
export function computeHash(data: Buffer) {
|
@@ -11,40 +11,51 @@ export type BuildContextLike = {
|
|
11
11
|
|
12
12
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
13
13
|
|
14
|
-
export async function
|
14
|
+
export async function getExtensionModuleFileSourceCodeReadyToBeCopied(params: {
|
15
15
|
buildContext: BuildContextLike;
|
16
16
|
fileRelativePath: string;
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
isOwnershipAction: boolean;
|
18
|
+
extensionModuleDirPath: string;
|
19
|
+
extensionModuleName: string;
|
20
|
+
extensionModuleVersion: string;
|
21
21
|
}): Promise<Buffer> {
|
22
22
|
const {
|
23
23
|
buildContext,
|
24
|
-
|
24
|
+
extensionModuleDirPath,
|
25
25
|
fileRelativePath,
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
isOwnershipAction,
|
27
|
+
extensionModuleName,
|
28
|
+
extensionModuleVersion
|
29
29
|
} = params;
|
30
30
|
|
31
31
|
let sourceCode = (
|
32
|
-
await fsPr.readFile(
|
32
|
+
await fsPr.readFile(
|
33
|
+
pathJoin(extensionModuleDirPath, KEYCLOAK_THEME, fileRelativePath)
|
34
|
+
)
|
33
35
|
).toString("utf8");
|
34
36
|
|
35
37
|
sourceCode = addCommentToSourceCode({
|
36
38
|
sourceCode,
|
37
39
|
fileRelativePath,
|
38
|
-
commentLines:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
commentLines: (() => {
|
41
|
+
const path = fileRelativePath.split(pathSep).join("/");
|
42
|
+
|
43
|
+
return isOwnershipAction
|
44
|
+
? [
|
45
|
+
`This file has been claimed for ownership from ${extensionModuleName} version ${extensionModuleVersion}.`,
|
46
|
+
`To relinquish ownership and restore this file to its original content, run the following command:`,
|
47
|
+
``,
|
48
|
+
`$ npx keycloakify own --path '${path}' --revert`
|
49
|
+
]
|
50
|
+
: [
|
51
|
+
`WARNING: Before modifying this file, run the following command:`,
|
52
|
+
``,
|
53
|
+
`$ npx keycloakify own --path '${path}'`,
|
54
|
+
``,
|
55
|
+
`This file is provided by ${extensionModuleName} version ${extensionModuleVersion}.`,
|
56
|
+
`It was copied into your repository by the postinstall script: \`keycloakify sync-extensions\`.`
|
57
|
+
];
|
58
|
+
})()
|
48
59
|
});
|
49
60
|
|
50
61
|
const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
|
@@ -93,7 +104,7 @@ function addCommentToSourceCode(params: {
|
|
93
104
|
`<!--`,
|
94
105
|
...commentLines.map(
|
95
106
|
line =>
|
96
|
-
` ${line.replace("--
|
107
|
+
` ${line.replace("--path", "-p").replace("Before modifying", "Before modifying or replacing")}`
|
97
108
|
),
|
98
109
|
`-->`
|
99
110
|
].join("\n");
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./sync-extension";
|