keycloakify 11.8.46 → 11.8.47-rc.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/254.index.js +283 -0
- package/bin/30.index.js +25 -0
- package/bin/{864.index.js → 309.index.js} +6944 -28439
- package/bin/311.index.js +198 -0
- package/bin/{313.index.js → 355.index.js} +148 -172
- package/bin/{84.index.js → 502.index.js} +151 -103
- package/bin/626.index.js +216 -0
- package/bin/656.index.js +274 -0
- package/bin/675.index.js +177 -0
- package/bin/69.index.js +1 -1
- package/bin/762.index.js +1475 -0
- package/bin/780.index.js +4 -2
- package/bin/786.index.js +115 -0
- package/bin/895.index.js +21501 -0
- package/bin/{618.index.js → 932.index.js} +117 -163
- package/bin/949.index.js +1 -1
- package/bin/97.index.js +539 -4
- package/bin/init/index.d.ts +1 -0
- package/bin/init/init.d.ts +3 -0
- package/bin/init/setupEslint.d.ts +4 -0
- package/bin/init/setupVitePluginIfNeeded.d.ts +4 -0
- package/bin/initialize-login-theme.d.ts +4 -0
- package/bin/main.js +42 -49
- package/bin/shared/customHandler.d.ts +1 -1
- package/bin/shared/customHandler.js.map +1 -1
- package/package.json +23 -7
- package/src/bin/init/index.ts +1 -0
- package/src/bin/init/init.ts +354 -0
- package/src/bin/init/setupEslint.ts +80 -0
- package/src/bin/init/setupVitePluginIfNeeded.ts +143 -0
- package/src/bin/initialize-account-theme/initialize-account-theme.ts +4 -0
- package/src/bin/initialize-login-theme.ts +323 -0
- package/src/bin/main.ts +14 -0
- package/src/bin/shared/buildContext.ts +28 -59
- package/src/bin/shared/customHandler.ts +3 -1
- package/src/bin/shared/initializeSpa.ts +28 -0
- package/src/bin/sync-extensions/extensionModuleMeta.ts +89 -73
- package/src/bin/sync-extensions/managedGitignoreFiles.ts +32 -2
- package/src/bin/tools/fetchProxyOptions.ts +2 -1
- package/src/bin/tools/npmInstall.ts +13 -6
- package/vite-plugin/index.js +24 -43
- package/bin/433.index.js +0 -140
- package/bin/698.index.js +0 -298
@@ -0,0 +1,80 @@
|
|
1
|
+
import { join as pathJoin } from "path";
|
2
|
+
import { existsAsync } from "../tools/fs.existsAsync";
|
3
|
+
import * as fs from "fs/promises";
|
4
|
+
import * as recast from "recast";
|
5
|
+
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
6
|
+
import * as babelParser from "@babel/parser";
|
7
|
+
import babelGenerate from "@babel/generator";
|
8
|
+
import * as babelTypes from "@babel/types";
|
9
|
+
|
10
|
+
/** This function will just set reportUnusedDisableDirectives to off so that we don't get warning on generated files */
|
11
|
+
export async function setupEslint(params: { projectDirPath: string }) {
|
12
|
+
const { projectDirPath } = params;
|
13
|
+
|
14
|
+
const eslintConfigJsFilePath = pathJoin(projectDirPath, "eslint.config.js");
|
15
|
+
|
16
|
+
if (!(await existsAsync(eslintConfigJsFilePath))) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const eslintConfigJsContent = (await fs.readFile(eslintConfigJsFilePath)).toString(
|
21
|
+
"utf8"
|
22
|
+
);
|
23
|
+
|
24
|
+
if (eslintConfigJsContent.includes("reportUnusedDisableDirectives")) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
const root = recast.parse(eslintConfigJsContent, {
|
29
|
+
parser: {
|
30
|
+
parse: (code: string) =>
|
31
|
+
babelParser.parse(code, {
|
32
|
+
sourceType: "module",
|
33
|
+
plugins: ["typescript"]
|
34
|
+
})
|
35
|
+
}
|
36
|
+
});
|
37
|
+
|
38
|
+
recast.visit(root, {
|
39
|
+
visitExportDefaultDeclaration(path) {
|
40
|
+
// @ts-expect-error
|
41
|
+
const args = path.node.declaration.arguments;
|
42
|
+
|
43
|
+
if (!Array.isArray(args)) return false;
|
44
|
+
|
45
|
+
args.push(
|
46
|
+
babelTypes.objectExpression([
|
47
|
+
babelTypes.objectProperty(
|
48
|
+
babelTypes.identifier("linterOptions"),
|
49
|
+
babelTypes.objectExpression([
|
50
|
+
babelTypes.objectProperty(
|
51
|
+
babelTypes.identifier("reportUnusedDisableDirectives"),
|
52
|
+
babelTypes.stringLiteral("off")
|
53
|
+
)
|
54
|
+
])
|
55
|
+
)
|
56
|
+
])
|
57
|
+
);
|
58
|
+
|
59
|
+
return false;
|
60
|
+
}
|
61
|
+
});
|
62
|
+
|
63
|
+
let eslintConfigJsContent_modified = babelGenerate(root).code;
|
64
|
+
|
65
|
+
format: {
|
66
|
+
if (!(await getIsPrettierAvailable())) {
|
67
|
+
break format;
|
68
|
+
}
|
69
|
+
|
70
|
+
eslintConfigJsContent_modified = await runPrettier({
|
71
|
+
sourceCode: eslintConfigJsContent_modified,
|
72
|
+
filePath: eslintConfigJsFilePath
|
73
|
+
});
|
74
|
+
}
|
75
|
+
|
76
|
+
await fs.writeFile(
|
77
|
+
eslintConfigJsFilePath,
|
78
|
+
Buffer.from(eslintConfigJsContent_modified, "utf8")
|
79
|
+
);
|
80
|
+
}
|
@@ -0,0 +1,143 @@
|
|
1
|
+
import { join as pathJoin } from "path";
|
2
|
+
import { existsAsync } from "../tools/fs.existsAsync";
|
3
|
+
import * as fs from "fs/promises";
|
4
|
+
import * as recast from "recast";
|
5
|
+
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
6
|
+
import * as babelParser from "@babel/parser";
|
7
|
+
import babelGenerate from "@babel/generator";
|
8
|
+
import * as babelTypes from "@babel/types";
|
9
|
+
|
10
|
+
/** Best effort to setup the Keycloakify vite plugin automatically */
|
11
|
+
export async function setupVitePluginIfNeeded(params: { projectDirPath: string }) {
|
12
|
+
const { projectDirPath } = params;
|
13
|
+
|
14
|
+
const viteConfigTsFilePath = pathJoin(projectDirPath, "vite.config.ts");
|
15
|
+
|
16
|
+
if (!(await existsAsync(viteConfigTsFilePath))) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const viteConfigTsContent = (await fs.readFile(viteConfigTsFilePath)).toString(
|
21
|
+
"utf8"
|
22
|
+
);
|
23
|
+
|
24
|
+
if (viteConfigTsContent.includes("keycloakify")) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
const root = recast.parse(viteConfigTsContent, {
|
29
|
+
parser: {
|
30
|
+
parse: (code: string) =>
|
31
|
+
babelParser.parse(code, {
|
32
|
+
sourceType: "module",
|
33
|
+
plugins: ["typescript"]
|
34
|
+
}),
|
35
|
+
generator: babelGenerate,
|
36
|
+
types: babelTypes
|
37
|
+
}
|
38
|
+
});
|
39
|
+
|
40
|
+
/* Before:
|
41
|
+
import { defineConfig } from "vite";
|
42
|
+
import react from "@vitejs/plugin-react";
|
43
|
+
|
44
|
+
// https://vitejs.dev/config/
|
45
|
+
export default defineConfig({
|
46
|
+
plugins: [ react() ]
|
47
|
+
});
|
48
|
+
*/
|
49
|
+
|
50
|
+
/* After:
|
51
|
+
import { defineConfig } from "vite";
|
52
|
+
import react from "@vitejs/plugin-react";
|
53
|
+
import { keycloakify } from "keycloakify/vite-plugin";
|
54
|
+
|
55
|
+
// https://vitejs.dev/config/
|
56
|
+
export default defineConfig({
|
57
|
+
plugins: [
|
58
|
+
react(),
|
59
|
+
keycloakify({
|
60
|
+
accountThemeImplementation: "none"
|
61
|
+
})
|
62
|
+
]
|
63
|
+
});
|
64
|
+
*/
|
65
|
+
|
66
|
+
recast.visit(root, {
|
67
|
+
visitProgram(path) {
|
68
|
+
const body = path.node.body;
|
69
|
+
|
70
|
+
// Add import: import { keycloakify } from "keycloakify/vite-plugin";
|
71
|
+
const importDeclaration = babelTypes.importDeclaration(
|
72
|
+
[
|
73
|
+
babelTypes.importSpecifier(
|
74
|
+
babelTypes.identifier("keycloakify"),
|
75
|
+
babelTypes.identifier("keycloakify")
|
76
|
+
)
|
77
|
+
],
|
78
|
+
babelTypes.stringLiteral("keycloakify/vite-plugin")
|
79
|
+
);
|
80
|
+
// @ts-expect-error
|
81
|
+
body.unshift(importDeclaration);
|
82
|
+
|
83
|
+
this.traverse(path);
|
84
|
+
},
|
85
|
+
visitCallExpression(path) {
|
86
|
+
const { node } = path;
|
87
|
+
|
88
|
+
if (
|
89
|
+
// @ts-expect-error
|
90
|
+
babelTypes.isIdentifier(node.callee, { name: "defineConfig" }) &&
|
91
|
+
node.arguments.length === 1 &&
|
92
|
+
// @ts-expect-error
|
93
|
+
babelTypes.isObjectExpression(node.arguments[0])
|
94
|
+
) {
|
95
|
+
const configObject = node.arguments[0];
|
96
|
+
const pluginsProp = configObject.properties.find(
|
97
|
+
prop =>
|
98
|
+
// @ts-expect-error
|
99
|
+
babelTypes.isObjectProperty(prop) &&
|
100
|
+
babelTypes.isIdentifier(prop.key, { name: "plugins" }) &&
|
101
|
+
babelTypes.isArrayExpression(prop.value)
|
102
|
+
) as babelTypes.ObjectProperty | undefined;
|
103
|
+
|
104
|
+
if (pluginsProp && babelTypes.isArrayExpression(pluginsProp.value)) {
|
105
|
+
// Append keycloakify plugin config
|
106
|
+
const keycloakifyCall = babelTypes.callExpression(
|
107
|
+
babelTypes.identifier("keycloakify"),
|
108
|
+
[
|
109
|
+
babelTypes.objectExpression([
|
110
|
+
babelTypes.objectProperty(
|
111
|
+
babelTypes.identifier("accountThemeImplementation"),
|
112
|
+
babelTypes.stringLiteral("none")
|
113
|
+
)
|
114
|
+
])
|
115
|
+
]
|
116
|
+
);
|
117
|
+
|
118
|
+
pluginsProp.value.elements.push(keycloakifyCall);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
this.traverse(path);
|
123
|
+
}
|
124
|
+
});
|
125
|
+
|
126
|
+
let viteConfigTsContent_modified = babelGenerate(root).code;
|
127
|
+
|
128
|
+
format: {
|
129
|
+
if (!(await getIsPrettierAvailable())) {
|
130
|
+
break format;
|
131
|
+
}
|
132
|
+
|
133
|
+
viteConfigTsContent_modified = await runPrettier({
|
134
|
+
sourceCode: viteConfigTsContent_modified,
|
135
|
+
filePath: viteConfigTsFilePath
|
136
|
+
});
|
137
|
+
}
|
138
|
+
|
139
|
+
await fs.writeFile(
|
140
|
+
viteConfigTsFilePath,
|
141
|
+
Buffer.from(viteConfigTsContent_modified, "utf8")
|
142
|
+
);
|
143
|
+
}
|
@@ -26,12 +26,16 @@ export async function command(params: { buildContext: BuildContext }) {
|
|
26
26
|
projectDirPath: buildContext.projectDirPath
|
27
27
|
});
|
28
28
|
|
29
|
+
console.log(chalk.cyan("Which account theme type?"));
|
30
|
+
|
29
31
|
const { value: accountThemeType } = await cliSelect({
|
30
32
|
values: ["Single-Page" as const, "Multi-Page" as const]
|
31
33
|
}).catch(() => {
|
32
34
|
process.exit(-1);
|
33
35
|
});
|
34
36
|
|
37
|
+
console.log(`${accountThemeType}\n`);
|
38
|
+
|
35
39
|
switch (accountThemeType) {
|
36
40
|
case "Multi-Page":
|
37
41
|
{
|
@@ -0,0 +1,323 @@
|
|
1
|
+
import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
|
2
|
+
import { dirname as pathDirname, join as pathJoin } from "path";
|
3
|
+
import type { BuildContext } from "./shared/buildContext";
|
4
|
+
import * as fs from "fs/promises";
|
5
|
+
import { assert, is, type Equals } from "tsafe/assert";
|
6
|
+
import { id } from "tsafe/id";
|
7
|
+
import { addSyncExtensionsToPostinstallScript } from "./shared/addSyncExtensionsToPostinstallScript";
|
8
|
+
import { getIsPrettierAvailable, runPrettier } from "./tools/runPrettier";
|
9
|
+
import { npmInstall } from "./tools/npmInstall";
|
10
|
+
import * as child_process from "child_process";
|
11
|
+
import { z } from "zod";
|
12
|
+
import chalk from "chalk";
|
13
|
+
import cliSelect from "cli-select";
|
14
|
+
import { existsAsync } from "./tools/fs.existsAsync";
|
15
|
+
|
16
|
+
export async function command(params: { buildContext: BuildContext }) {
|
17
|
+
const { buildContext } = params;
|
18
|
+
|
19
|
+
const { hasBeenHandled } = await maybeDelegateCommandToCustomHandler({
|
20
|
+
commandName: "initialize-login-theme",
|
21
|
+
buildContext
|
22
|
+
});
|
23
|
+
|
24
|
+
if (hasBeenHandled) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
if (
|
29
|
+
buildContext.implementedThemeTypes.login.isImplemented ||
|
30
|
+
buildContext.implementedThemeTypes.login.isImplemented_native
|
31
|
+
) {
|
32
|
+
console.warn(chalk.red("There is already a login theme in your project"));
|
33
|
+
|
34
|
+
process.exit(-1);
|
35
|
+
}
|
36
|
+
|
37
|
+
const parsedPackageJson = await (async () => {
|
38
|
+
type ParsedPackageJson = {
|
39
|
+
scripts?: Record<string, string | undefined>;
|
40
|
+
dependencies?: Record<string, string | undefined>;
|
41
|
+
devDependencies?: Record<string, string | undefined>;
|
42
|
+
};
|
43
|
+
|
44
|
+
const zParsedPackageJson = (() => {
|
45
|
+
type TargetType = ParsedPackageJson;
|
46
|
+
|
47
|
+
const zTargetType = z.object({
|
48
|
+
scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
|
49
|
+
dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
|
50
|
+
devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
|
51
|
+
});
|
52
|
+
|
53
|
+
assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
|
54
|
+
|
55
|
+
return id<z.ZodType<TargetType>>(zTargetType);
|
56
|
+
})();
|
57
|
+
const parsedPackageJson = JSON.parse(
|
58
|
+
(await fs.readFile(buildContext.packageJsonFilePath)).toString("utf8")
|
59
|
+
);
|
60
|
+
|
61
|
+
zParsedPackageJson.parse(parsedPackageJson);
|
62
|
+
|
63
|
+
assert(is<ParsedPackageJson>(parsedPackageJson));
|
64
|
+
|
65
|
+
return parsedPackageJson;
|
66
|
+
})();
|
67
|
+
|
68
|
+
addSyncExtensionsToPostinstallScript({
|
69
|
+
parsedPackageJson,
|
70
|
+
buildContext
|
71
|
+
});
|
72
|
+
|
73
|
+
const doInstallStories = await (async () => {
|
74
|
+
console.log(chalk.cyan(`\nDo you want to install the Stories?`));
|
75
|
+
|
76
|
+
const YES = "Yes (Recommended)";
|
77
|
+
const NO = "No";
|
78
|
+
|
79
|
+
const { value } = await cliSelect({
|
80
|
+
values: [YES, NO]
|
81
|
+
}).catch(() => {
|
82
|
+
process.exit(-1);
|
83
|
+
});
|
84
|
+
|
85
|
+
console.log(`${value}\n`);
|
86
|
+
|
87
|
+
return value === YES;
|
88
|
+
})();
|
89
|
+
|
90
|
+
install_storybook: {
|
91
|
+
if (!doInstallStories) {
|
92
|
+
break install_storybook;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (buildContext.bundler !== "vite") {
|
96
|
+
break install_storybook;
|
97
|
+
}
|
98
|
+
|
99
|
+
if (
|
100
|
+
Object.keys({
|
101
|
+
...parsedPackageJson.dependencies,
|
102
|
+
...parsedPackageJson.devDependencies
|
103
|
+
}).includes("storybook")
|
104
|
+
) {
|
105
|
+
break install_storybook;
|
106
|
+
}
|
107
|
+
|
108
|
+
(parsedPackageJson.scripts ??= {})["storybook"] = "storybook dev -p 6006";
|
109
|
+
parsedPackageJson.scripts["build-storybook"] = "storybook build";
|
110
|
+
|
111
|
+
(parsedPackageJson.devDependencies ??= {})["storybook"] = "^9.0.4";
|
112
|
+
parsedPackageJson.devDependencies["@storybook/react-vite"] = "^9.0.4";
|
113
|
+
|
114
|
+
const files: { relativeFilePath: string; fileContent: string }[] = [
|
115
|
+
{
|
116
|
+
relativeFilePath: "main.ts",
|
117
|
+
fileContent: [
|
118
|
+
`import type { StorybookConfig } from "@storybook/react-vite";`,
|
119
|
+
``,
|
120
|
+
`const config: StorybookConfig = {`,
|
121
|
+
` stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],`,
|
122
|
+
` addons: [],`,
|
123
|
+
` framework: {`,
|
124
|
+
` name: "@storybook/react-vite",`,
|
125
|
+
` options: {}`,
|
126
|
+
` },`,
|
127
|
+
`};`,
|
128
|
+
`export default config;`,
|
129
|
+
``
|
130
|
+
].join("\n")
|
131
|
+
},
|
132
|
+
{
|
133
|
+
relativeFilePath: "preview.ts",
|
134
|
+
fileContent: storybookPreviewTsFileContent
|
135
|
+
}
|
136
|
+
];
|
137
|
+
|
138
|
+
for (let { relativeFilePath, fileContent } of files) {
|
139
|
+
const filePath = pathJoin(
|
140
|
+
buildContext.projectDirPath,
|
141
|
+
".storybook",
|
142
|
+
relativeFilePath
|
143
|
+
);
|
144
|
+
|
145
|
+
{
|
146
|
+
const dirPath = pathDirname(filePath);
|
147
|
+
|
148
|
+
if (!(await existsAsync(dirPath))) {
|
149
|
+
await fs.mkdir(dirPath, { recursive: true });
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
run_prettier: {
|
154
|
+
if (!(await getIsPrettierAvailable())) {
|
155
|
+
break run_prettier;
|
156
|
+
}
|
157
|
+
|
158
|
+
fileContent = await runPrettier({
|
159
|
+
filePath: filePath,
|
160
|
+
sourceCode: fileContent
|
161
|
+
});
|
162
|
+
}
|
163
|
+
|
164
|
+
await fs.writeFile(filePath, Buffer.from(fileContent, "utf8"));
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
{
|
169
|
+
const moduleName = "@keycloakify/login-ui";
|
170
|
+
|
171
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
172
|
+
|
173
|
+
(parsedPackageJson.dependencies ??= {})[moduleName] = `~${latestVersion}`;
|
174
|
+
|
175
|
+
if (parsedPackageJson.devDependencies !== undefined) {
|
176
|
+
delete parsedPackageJson.devDependencies[moduleName];
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
install_stories: {
|
181
|
+
if (!doInstallStories) {
|
182
|
+
break install_stories;
|
183
|
+
}
|
184
|
+
|
185
|
+
const moduleName = "@keycloakify/login-ui-storybook";
|
186
|
+
|
187
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
188
|
+
|
189
|
+
(parsedPackageJson.devDependencies ??= {})[moduleName] = `~${latestVersion}`;
|
190
|
+
|
191
|
+
delete parsedPackageJson.dependencies[moduleName];
|
192
|
+
}
|
193
|
+
|
194
|
+
{
|
195
|
+
let sourceCode = JSON.stringify(parsedPackageJson, null, 2);
|
196
|
+
|
197
|
+
if (await getIsPrettierAvailable()) {
|
198
|
+
sourceCode = await runPrettier({
|
199
|
+
sourceCode,
|
200
|
+
filePath: buildContext.packageJsonFilePath
|
201
|
+
});
|
202
|
+
}
|
203
|
+
|
204
|
+
await fs.writeFile(
|
205
|
+
buildContext.packageJsonFilePath,
|
206
|
+
Buffer.from(sourceCode, "utf8")
|
207
|
+
);
|
208
|
+
}
|
209
|
+
|
210
|
+
await npmInstall({
|
211
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
215
|
+
async function getModuleLatestVersion(params: { moduleName: string }) {
|
216
|
+
const { moduleName } = params;
|
217
|
+
|
218
|
+
const versions = ((): string[] => {
|
219
|
+
const cmdOutput = child_process
|
220
|
+
.execSync(`npm show ${moduleName} versions --json`)
|
221
|
+
.toString("utf8")
|
222
|
+
.trim();
|
223
|
+
|
224
|
+
const versions = JSON.parse(cmdOutput) as string | string[];
|
225
|
+
|
226
|
+
// NOTE: Bug in some older npm versions
|
227
|
+
if (typeof versions === "string") {
|
228
|
+
return [versions];
|
229
|
+
}
|
230
|
+
|
231
|
+
return versions;
|
232
|
+
})();
|
233
|
+
|
234
|
+
const version = versions.reverse().filter(version => !version.includes("-"))[0];
|
235
|
+
|
236
|
+
assert(version !== undefined);
|
237
|
+
|
238
|
+
return version;
|
239
|
+
}
|
240
|
+
|
241
|
+
const storybookPreviewTsFileContent = [
|
242
|
+
`import type { Preview } from "@storybook/react-vite";`,
|
243
|
+
``,
|
244
|
+
`const preview: Preview = {`,
|
245
|
+
` parameters: {`,
|
246
|
+
` controls: {`,
|
247
|
+
` matchers: {`,
|
248
|
+
` color: /(background|color)$/i,`,
|
249
|
+
` date: /Date$/i`,
|
250
|
+
` }`,
|
251
|
+
` },`,
|
252
|
+
` options: {`,
|
253
|
+
` storySort: (a, b)=> {`,
|
254
|
+
``,
|
255
|
+
` const orderedPagesPrefix = [`,
|
256
|
+
` "Introduction",`,
|
257
|
+
` "login/login.ftl",`,
|
258
|
+
` "login/register.ftl",`,
|
259
|
+
` "login/terms.ftl",`,
|
260
|
+
` "login/error.ftl",`,
|
261
|
+
` "login/code.ftl",`,
|
262
|
+
` "login/delete-account-confirm.ftl",`,
|
263
|
+
` "login/delete-credential.ftl",`,
|
264
|
+
` "login/frontchannel-logout.ftl",`,
|
265
|
+
` "login/idp-review-user-profile.ftl",`,
|
266
|
+
` "login/info.ftl",`,
|
267
|
+
` "login/login-config-totp.ftl",`,
|
268
|
+
` "login/login-idp-link-confirm.ftl",`,
|
269
|
+
` "login/login-idp-link-email.ftl",`,
|
270
|
+
` "login/login-oauth-grant.ftl",`,
|
271
|
+
` "login/login-otp.ftl",`,
|
272
|
+
` "login/login-page-expired.ftl",`,
|
273
|
+
` "login/login-password.ftl",`,
|
274
|
+
` "login/login-reset-otp.ftl",`,
|
275
|
+
` "login/login-reset-password.ftl",`,
|
276
|
+
` "login/login-update-password.ftl",`,
|
277
|
+
` "login/login-update-profile.ftl",`,
|
278
|
+
` "login/login-username.ftl",`,
|
279
|
+
` "login/login-verify-email.ftl",`,
|
280
|
+
` "login/login-x509-info.ftl",`,
|
281
|
+
` "login/logout-confirm.ftl",`,
|
282
|
+
` "login/saml-post-form.ftl",`,
|
283
|
+
` "login/select-authenticator.ftl",`,
|
284
|
+
` "login/update-email.ftl",`,
|
285
|
+
` "login/webauthn-authenticate.ftl",`,
|
286
|
+
` "login/webauthn-error.ftl",`,
|
287
|
+
` "login/webauthn-register.ftl",`,
|
288
|
+
` "login/login-oauth2-device-verify-user-code.ftl",`,
|
289
|
+
` "login/login-recovery-authn-code-config.ftl",`,
|
290
|
+
` "login/login-recovery-authn-code-input.ftl",`,
|
291
|
+
` "account/account.ftl",`,
|
292
|
+
` "account/password.ftl",`,
|
293
|
+
` "account/federatedIdentity.ftl",`,
|
294
|
+
` "account/log.ftl",`,
|
295
|
+
` "account/sessions.ftl",`,
|
296
|
+
` "account/totp.ftl"`,
|
297
|
+
` ];`,
|
298
|
+
``,
|
299
|
+
` function getHardCodedWeight(title) {`,
|
300
|
+
` for (let i = 0; i < orderedPagesPrefix.length; i++) {`,
|
301
|
+
` if (`,
|
302
|
+
` title`,
|
303
|
+
` .toLowerCase()`,
|
304
|
+
` .startsWith(orderedPagesPrefix[i].toLowerCase())`,
|
305
|
+
` ) {`,
|
306
|
+
` return orderedPagesPrefix.length - i;`,
|
307
|
+
` }`,
|
308
|
+
` }`,
|
309
|
+
``,
|
310
|
+
` return 0;`,
|
311
|
+
` }`,
|
312
|
+
``,
|
313
|
+
` return getHardCodedWeight(b.title) - getHardCodedWeight(a.title);`,
|
314
|
+
``,
|
315
|
+
` }`,
|
316
|
+
``,
|
317
|
+
` }`,
|
318
|
+
` }`,
|
319
|
+
`};`,
|
320
|
+
``,
|
321
|
+
`export default preview;`,
|
322
|
+
``
|
323
|
+
].join("\n");
|
package/src/bin/main.ts
CHANGED
@@ -146,6 +146,20 @@ program
|
|
146
146
|
}
|
147
147
|
});
|
148
148
|
|
149
|
+
program
|
150
|
+
.command({
|
151
|
+
name: "init",
|
152
|
+
description: "(BETA) Initialize a new theme type (login/account/admin/email)"
|
153
|
+
})
|
154
|
+
.task({
|
155
|
+
skip,
|
156
|
+
handler: async ({ projectDirPath }) => {
|
157
|
+
const { command } = await import("./init");
|
158
|
+
|
159
|
+
await command({ projectDirPath: projectDirPath ?? process.cwd() });
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
149
163
|
program
|
150
164
|
.command({
|
151
165
|
name: "eject-page",
|