create-ec-app 0.0.5 → 0.0.6

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/dist/index.js CHANGED
@@ -1,95 +1,146 @@
1
1
  #!/usr/bin/env node
2
- import chalk from "chalk";
3
- import inquirer from "inquirer";
4
- import { createWebResourceApp } from "./creators/webresource.js";
5
- import { createPortalApp } from "./creators/portal.js";
6
- import { createPowerPagesApp } from "./creators/powerpages.js";
7
- import { createMobileApp } from "./creators/mobile.js";
8
- const main = async () => {
9
- console.log(chalk.bold.hex("#F5AB00")("\nEC App Creator\n"));
10
- console.log(chalk.gray("Create applications for your EC ecosystem.\n"));
11
- // Prompt for project name if not provided
12
- let projectName = process.argv[2];
13
- if (!projectName) {
14
- const { newProjectName } = await inquirer.prompt([
15
- {
16
- type: "input",
17
- name: "newProjectName",
18
- message: "What is the name of your project?",
19
- validate: (input) => input === "." ||
20
- /^([a-z0-9\-_])+$/.test(input) ||
21
- 'Project name may only include "." in order to use the parent directory name, lowercase letters, numbers, underscores, and hyphens.',
22
- },
23
- ]);
24
- projectName = newProjectName;
25
- }
26
- // Prompt for application type
27
- const appTypes = [
28
- {
29
- name: "Webresource App",
30
- value: "webresource",
31
- description: "React app for Dynamics 365 webresources with Vite, optional Kendo UI, and Tailwind"
32
- },
33
- {
34
- name: "Portal App",
35
- value: "portal",
36
- description: "Next.js app for customer portals with authentication and Dynamics integration"
37
- },
38
- {
39
- name: "Power Pages App",
40
- value: "powerpages",
41
- description: "React SPA for Power Pages with authentication context and data services"
42
- },
43
- {
44
- name: "Mobile App",
45
- value: "mobile",
46
- description: "React Native Expo app with TypeScript and NativeWind"
47
- }
48
- ];
49
- const { appType } = await inquirer.prompt([
50
- {
51
- type: "list",
52
- name: "appType",
53
- message: "What type of application would you like to create?",
54
- choices: appTypes.map(type => ({
55
- name: `${type.name}\n ${chalk.gray(type.description)}`,
56
- value: type.value,
57
- short: type.name
58
- })),
59
- pageSize: 10
2
+ import path, { dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { cancel, intro, isCancel, log, outro, select, spinner, text, } from "@clack/prompts";
5
+ import fs from "fs-extra";
6
+ import { applyLayer, replaceTokensRecursively } from "./libFunctions.js";
7
+ const { execSync } = await import("node:child_process");
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ async function main() {
11
+ intro("Create EC App");
12
+ const name = await text({
13
+ message: "Project name",
14
+ placeholder: "my-app",
15
+ validate(value) {
16
+ if (value.length === 0)
17
+ return "Project name cannot be empty";
18
+ if (value.toLocaleLowerCase() !== value)
19
+ return "Project name must be lowercase";
20
+ if (/\s/.test(value))
21
+ return "Project name cannot contain spaces";
22
+ if (/[^a-z0-9-_]/.test(value))
23
+ return "Project name can only contain letters, numbers, hyphens, and underscores";
60
24
  },
61
- ]);
62
- console.log(`\n${chalk.green("Creating")} ${chalk.bold(appType)} app: ${chalk.cyan(projectName)}\n`);
63
- // Route to the appropriate creator
64
- switch (appType) {
65
- case "webresource":
66
- await createWebResourceApp(projectName);
67
- break;
68
- case "portal":
69
- await createPortalApp(projectName);
70
- break;
71
- case "powerpages":
72
- await createPowerPagesApp(projectName);
73
- break;
74
- case "mobile":
75
- await createMobileApp(projectName);
76
- break;
77
- default:
78
- console.error(chalk.red(`Unknown app type: ${appType}`));
79
- process.exit(1);
25
+ });
26
+ if (isCancel(name)) {
27
+ cancel("Operation cancelled.");
28
+ process.exit(0);
29
+ }
30
+ const projectName = String(name).trim();
31
+ log.step(`Creating project: ${projectName}`);
32
+ const target = await select({
33
+ message: "What are you building?",
34
+ options: [
35
+ { label: "Web Resource", value: "webresource" },
36
+ { label: "Portal (WIP)", value: "portal" },
37
+ { label: "Static Web App", value: "swa" },
38
+ { label: "Power Pages", value: "power-pages" },
39
+ ],
40
+ });
41
+ if (isCancel(target)) {
42
+ cancel("Operation cancelled.");
43
+ process.exit(0);
44
+ }
45
+ log.step(`Selected target: ${target}`);
46
+ const uiType = await select({
47
+ message: "What UI library do you want to use?",
48
+ options: [
49
+ { label: "Kendo UI", value: "kendo" },
50
+ { label: "Shadcn/UI", value: "shadcn-ui" },
51
+ ],
52
+ });
53
+ if (isCancel(uiType)) {
54
+ cancel("Operation cancelled.");
55
+ process.exit(0);
56
+ }
57
+ const shouldRunNpmInstall = await select({
58
+ message: "Do you want to install dependencies?",
59
+ options: [
60
+ { label: "Yes", value: { run: true } },
61
+ { label: "No", value: { run: false } },
62
+ ],
63
+ });
64
+ if (isCancel(shouldRunNpmInstall)) {
65
+ cancel("Operation cancelled.");
66
+ process.exit(0);
80
67
  }
81
- // Final success message
82
- console.log(chalk.green.bold("\nProject created successfully."));
83
- console.log(`\n${chalk.cyan("Next steps:")}`);
84
- console.log(` - cd ${projectName}`);
85
- if (appType === "webresource" || appType === "powerpages") {
86
- console.log(` - If you selected Kendo UI: ${chalk.yellow("npx kendo-ui-license activate")}`);
68
+ const projectDir = path.join(process.cwd(), projectName);
69
+ const templatesRoot = path.join(__dirname, "..", "templates");
70
+ const baseDir = path.join(templatesRoot, "base");
71
+ const targetDir = path.join(templatesRoot, "targets", target);
72
+ const uiDir = path.join(templatesRoot, "ui", uiType);
73
+ await fs.copy(baseDir, projectDir);
74
+ if (fs.existsSync(targetDir)) {
75
+ await applyLayer(targetDir, projectDir);
87
76
  }
88
- console.log(` - npm run dev`);
89
- console.log(` - npm run build\n`);
90
- };
91
- main().catch((error) => {
92
- console.error(chalk.red("An error occurred:"), error);
77
+ if (fs.existsSync(uiDir)) {
78
+ await applyLayer(uiDir, projectDir);
79
+ }
80
+ await replaceTokensRecursively(projectDir, {
81
+ APP_NAME: projectName,
82
+ TARGET: target,
83
+ UI: uiType,
84
+ });
85
+ //WARN: This is a special case fix for having AuthContext in Kendo for Power Pages
86
+ if (target === "power-pages" && uiType === "kendo") {
87
+ const mainTsxPath = path.join(projectDir, "src", "main.tsx");
88
+ await fs.writeFile(mainTsxPath, POWER_PAGES_KENDO_MAIN_TSX, "utf-8");
89
+ }
90
+ if (shouldRunNpmInstall.run) {
91
+ const s = spinner();
92
+ s.start("Running npm install...");
93
+ const { execSync } = await import("node:child_process");
94
+ execSync("npm install", { cwd: projectDir, stdio: "inherit" });
95
+ s.stop("Dependencies installed.");
96
+ }
97
+ const sGit = spinner();
98
+ sGit.start("Initializing git repository...");
99
+ execSync("git init", { cwd: projectDir, stdio: "ignore" });
100
+ execSync("git add .", { cwd: projectDir, stdio: "ignore" });
101
+ execSync('git commit -m "Initial commit"', {
102
+ cwd: projectDir,
103
+ stdio: "ignore",
104
+ });
105
+ sGit.stop("Git repository initialized.");
106
+ outro(`Scaffolded ${projectName} as ${target} with ${uiType}. Next steps: 'git remote origin add <url>'`);
107
+ }
108
+ main().catch((err) => {
109
+ console.error(err);
93
110
  process.exit(1);
94
111
  });
112
+ // NOTE: Constants
113
+ const POWER_PAGES_KENDO_MAIN_TSX = `import { StrictMode } from "react";
114
+ import { createRoot } from "react-dom/client";
115
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
116
+ import "@progress/kendo-theme-fluent/dist/all.css";
117
+ import "./index.css";
118
+ import App from "./App.tsx";
119
+
120
+ import { AuthProvider } from "./context/AuthContext.tsx";
121
+
122
+ const queryClient = new QueryClient({
123
+ defaultOptions: {
124
+ queries: {
125
+ refetchOnWindowFocus: false,
126
+ retry: 3,
127
+ staleTime: 5 * 60 * 1000, // 5 minutes
128
+ },
129
+ mutations: {
130
+ retry: 1,
131
+ },
132
+ },
133
+ });
134
+
135
+ const root = createRoot(document.getElementById("root")!);
136
+
137
+ root.render(
138
+ <StrictMode>
139
+ <AuthProvider>
140
+ <QueryClientProvider client={queryClient}>
141
+ <App />
142
+ </QueryClientProvider>
143
+ </AuthProvider>
144
+ </StrictMode>
145
+ );`;
95
146
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Applies a template later onto an existing base project
3
+ * @param { string } layerDir - the base directory of the layer to patch
4
+ * @param { string } projectDir - the base directory of the files to be patched
5
+ * */
6
+ export declare function applyLayer(layerDir: string, projectDir: string): Promise<void>;
7
+ /**
8
+ * Safely reads a JSON file if it exists.
9
+ *
10
+ * If the file does not exist, returns `undefined` instead of throwing.
11
+ *
12
+ * @param {string} filePath - Absolute path to the JSON file.
13
+ * @returns {Promise<any | undefined>} The parsed JSON object or `undefined` if the file does not exist.
14
+ */
15
+ export declare function readJsonIfExists(filePath: string): Promise<any | undefined>;
16
+ /**
17
+ * Merges two JSON objects with special handling for dependency-style keys.
18
+ *
19
+ * Shallow merges the root object, then deep-merges the following keys:
20
+ * - dependencies
21
+ * - devDependencies
22
+ * - peerDependencies
23
+ * - scripts
24
+ *
25
+ * Patch values always override base values on conflicts.
26
+ *
27
+ * @param {any} base - The base JSON object (from the base template).
28
+ * @param {any} patch - The patch JSON object (from a layer).
29
+ * @returns {any} The merged JSON result.
30
+ */
31
+ export declare function mergeJson(base: any, patch: any): any;
32
+ /**
33
+ * Recursively replaces {{TOKEN}} placeholders in all text files under a directory.
34
+ *
35
+ * Traverses the directory tree depth-first. Each file is treated as UTF-8 text.
36
+ * If a file cannot be read as text (binary), it is skipped silently.
37
+ *
38
+ * @param {string} rootDir - Root directory to begin token replacement.
39
+ * @param {Record<string, string>} tokens - Key/value pairs used for replacement.
40
+ */
41
+ export declare function replaceTokensRecursively(rootDir: string, tokens: Record<string, string>): Promise<void>;
42
+ //# sourceMappingURL=libFunctions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"libFunctions.d.ts","sourceRoot":"","sources":["../src/libFunctions.ts"],"names":[],"mappings":"AAGA;;;;KAIK;AACL,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBA6CpE;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAK1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAoBpD;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,iBA4B9B"}
@@ -0,0 +1,121 @@
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ /**
4
+ * Applies a template later onto an existing base project
5
+ * @param { string } layerDir - the base directory of the layer to patch
6
+ * @param { string } projectDir - the base directory of the files to be patched
7
+ * */
8
+ export async function applyLayer(layerDir, projectDir) {
9
+ const entries = await fs.readdir(layerDir, { withFileTypes: true });
10
+ for (const entry of entries) {
11
+ const layerPath = path.join(layerDir, entry.name);
12
+ const relPath = path.relative(layerDir, layerPath);
13
+ if (entry.isDirectory()) {
14
+ await applyLayer(layerPath, path.join(projectDir, entry.name));
15
+ continue;
16
+ }
17
+ if (entry.name.endsWith(".patch.json")) {
18
+ const targetRel = relPath.replace(/\.patch\.json$/, ".json");
19
+ const targetPath = path.join(projectDir, targetRel);
20
+ await fs.ensureDir(path.dirname(targetPath));
21
+ const baseJson = (await readJsonIfExists(targetPath)) ?? {};
22
+ const patchJson = await fs.readJson(layerPath);
23
+ const merged = mergeJson(baseJson, patchJson);
24
+ await fs.writeJson(targetPath, merged, { spaces: 2 });
25
+ continue;
26
+ }
27
+ if (/\.(patch\.ts|patch\.tsx|patch\.js|patch\.jsx|patch\.css)$/.test(entry.name)) {
28
+ const targetRel = relPath.replace(".patch.", ".");
29
+ const targetPath = path.join(projectDir, targetRel);
30
+ await fs.ensureDir(path.dirname(targetPath));
31
+ await fs.copy(layerPath, targetPath);
32
+ continue;
33
+ }
34
+ const targetPath = path.join(projectDir, relPath);
35
+ await fs.ensureDir(path.dirname(targetPath));
36
+ await fs.copy(layerPath, targetPath);
37
+ }
38
+ }
39
+ /**
40
+ * Safely reads a JSON file if it exists.
41
+ *
42
+ * If the file does not exist, returns `undefined` instead of throwing.
43
+ *
44
+ * @param {string} filePath - Absolute path to the JSON file.
45
+ * @returns {Promise<any | undefined>} The parsed JSON object or `undefined` if the file does not exist.
46
+ */
47
+ export async function readJsonIfExists(filePath) {
48
+ if (!(await fs.pathExists(filePath))) {
49
+ return undefined;
50
+ }
51
+ return fs.readJson(filePath);
52
+ }
53
+ /**
54
+ * Merges two JSON objects with special handling for dependency-style keys.
55
+ *
56
+ * Shallow merges the root object, then deep-merges the following keys:
57
+ * - dependencies
58
+ * - devDependencies
59
+ * - peerDependencies
60
+ * - scripts
61
+ *
62
+ * Patch values always override base values on conflicts.
63
+ *
64
+ * @param {any} base - The base JSON object (from the base template).
65
+ * @param {any} patch - The patch JSON object (from a layer).
66
+ * @returns {any} The merged JSON result.
67
+ */
68
+ export function mergeJson(base, patch) {
69
+ const result = { ...base, ...patch };
70
+ const mergeKeys = [
71
+ "dependencies",
72
+ "devDependencies",
73
+ "peerDependencies",
74
+ "scripts",
75
+ ];
76
+ for (const key of mergeKeys) {
77
+ if (base?.[key] || patch?.[key]) {
78
+ result[key] = {
79
+ ...(base?.[key] ?? {}),
80
+ ...(patch?.[key] ?? {}),
81
+ };
82
+ }
83
+ }
84
+ return result;
85
+ }
86
+ /**
87
+ * Recursively replaces {{TOKEN}} placeholders in all text files under a directory.
88
+ *
89
+ * Traverses the directory tree depth-first. Each file is treated as UTF-8 text.
90
+ * If a file cannot be read as text (binary), it is skipped silently.
91
+ *
92
+ * @param {string} rootDir - Root directory to begin token replacement.
93
+ * @param {Record<string, string>} tokens - Key/value pairs used for replacement.
94
+ */
95
+ export async function replaceTokensRecursively(rootDir, tokens) {
96
+ const entries = await fs.readdir(rootDir, { withFileTypes: true });
97
+ for (const entry of entries) {
98
+ const fullPath = path.join(rootDir, entry.name);
99
+ if (entry.isDirectory()) {
100
+ await replaceTokensRecursively(fullPath, tokens);
101
+ }
102
+ else {
103
+ let content;
104
+ try {
105
+ content = await fs.readFile(fullPath, "utf8");
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ let updated = content;
111
+ for (const [key, value] of Object.entries(tokens)) {
112
+ const pattern = new RegExp(`{{${key}}}`, "g");
113
+ updated = updated.replace(pattern, value);
114
+ }
115
+ if (updated !== content) {
116
+ await fs.writeFile(fullPath, updated, "utf8");
117
+ }
118
+ }
119
+ }
120
+ }
121
+ //# sourceMappingURL=libFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"libFunctions.js","sourceRoot":"","sources":["../src/libFunctions.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,60 +1,55 @@
1
1
  {
2
- "name": "create-ec-app",
3
- "version": "0.0.5",
4
- "description": "Unified CLI tool to create different types of EC applications: Webresource, Portal, Power Pages, and Mobile apps.",
5
- "main": "dist/index.js",
6
- "type": "module",
7
- "bin": {
8
- "create-ec-app": "bin/index.js"
9
- },
10
- "scripts": {
11
- "build": "tsc && node scripts/copy-assets.mjs",
12
- "dev": "tsc --watch",
13
- "test": "node bin/index.js test-app",
14
- "prepublishOnly": "npm run build"
15
- },
16
- "keywords": [
17
- "react",
18
- "vite",
19
- "nextjs",
20
- "expo",
21
- "kendo",
22
- "tailwind",
23
- "cli",
24
- "powerpages",
25
- "portal",
26
- "mobile",
27
- "webresource",
28
- "dynamics",
29
- "ec"
30
- ],
31
- "author": "Schalk Conradie",
32
- "license": "MIT",
33
- "dependencies": {
34
- "chalk": "^5.3.0",
35
- "fs-extra": "^11.2.0",
36
- "inquirer": "^12.6.3",
37
- "ora": "^8.0.1"
38
- },
39
- "devDependencies": {
40
- "@types/node": "^22.8.6",
41
- "@types/fs-extra": "^11.0.4",
42
- "@types/inquirer": "^9.0.7",
43
- "typescript": "^5.6.3"
44
- },
45
- "engines": {
46
- "node": ">=18.0.0"
47
- },
48
- "files": [
49
- "dist/**/*",
50
- "bin/**/*"
51
- ],
52
- "repository": {
53
- "type": "git",
54
- "url": "git+https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app.git"
55
- },
56
- "bugs": {
57
- "url": "https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app/issues"
58
- },
59
- "homepage": "https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app#readme"
60
- }
2
+ "name": "create-ec-app",
3
+ "version": "0.0.6",
4
+ "description": "Unified CLI tool to create different types of EC applications: Webresource, Portal, Power Pages",
5
+ "bin": {
6
+ "create-ec-app": "./dist/index.js"
7
+ },
8
+ "scripts": {
9
+ "dev": "tsx src/index.ts",
10
+ "build": "tsc -p tsconfig.json",
11
+ "test": "node bin/index.js test-app",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "react",
16
+ "vite",
17
+ "kendo",
18
+ "tailwind",
19
+ "cli",
20
+ "powerpages",
21
+ "portal",
22
+ "webresource",
23
+ "dynamics",
24
+ "ec"
25
+ ],
26
+ "engines": {
27
+ "node": ">=22.0.0"
28
+ },
29
+ "files": [
30
+ "dist/**/*",
31
+ "bin/**/*"
32
+ ],
33
+ "author": "Schalk Conradie",
34
+ "type": "module",
35
+ "dependencies": {
36
+ "@clack/prompts": "^0.11.0",
37
+ "fs-extra": "^11.3.2"
38
+ },
39
+ "devDependencies": {
40
+ "@types/fs-extra": "^11.0.4",
41
+ "@types/node": "^24.10.1",
42
+ "ts-node": "^10.9.2",
43
+ "tsx": "^4.21.0",
44
+ "typescript": "^5.9.3"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app/issues"
52
+ },
53
+ "homepage": "https://github.com/Enterprisecloud-Pty-Ltd/create-ec-app#readme"
54
+ }
55
+