untitledui 0.1.1
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/commands/add.js +339 -0
- package/dist/commands/init.js +436 -0
- package/dist/helper/download-tar-api.js +129 -0
- package/dist/helper/download-tar.js +81 -0
- package/dist/helper/find-css-file.js +19 -0
- package/dist/helper/formatText.js +37 -0
- package/dist/helper/get-components-api.js +47 -0
- package/dist/helper/get-components-list.js +62 -0
- package/dist/helper/get-components.js +19 -0
- package/dist/helper/get-config.js +163 -0
- package/dist/helper/get-package-info.js +99 -0
- package/dist/helper/get-pkg-manager.js +16 -0
- package/dist/helper/get-project.js +176 -0
- package/dist/helper/install-template.js +29 -0
- package/dist/helper/match-color-css.js +82 -0
- package/dist/helper/update-color-css.js +134 -0
- package/dist/index.js +25 -0
- package/dist/package.json +50 -0
- package/dist/res/components.json +520 -0
- package/dist/res/config.json +3 -0
- package/package.json +61 -0
- package/templates/default/.prettierrc +10 -0
- package/templates/default/README.md +36 -0
- package/templates/default/eslint.config.mjs +58 -0
- package/templates/default/next.config.ts +6 -0
- package/templates/default/package.json +57 -0
- package/templates/default/postcss.config.js +5 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/marketing/smiling-girl.png +0 -0
- package/templates/default/public/marketing/spirals.webp +0 -0
- package/templates/default/src/app/home-screen.tsx +109 -0
- package/templates/default/src/app/layout.tsx +42 -0
- package/templates/default/src/app/not-found.tsx +40 -0
- package/templates/default/src/app/page.tsx +3 -0
- package/templates/default/src/components/foundations/dot-icon.tsx +27 -0
- package/templates/default/src/components/foundations/featured-icon/featured-icons.tsx +153 -0
- package/templates/default/src/components/foundations/logo/UntitledLogo.tsx +63 -0
- package/templates/default/src/components/foundations/logo/UntitledLogoMinimal.tsx +164 -0
- package/templates/default/src/components/foundations/payment-icons/amex-icon.tsx +19 -0
- package/templates/default/src/components/foundations/payment-icons/apple-pay-icon.tsx +27 -0
- package/templates/default/src/components/foundations/payment-icons/discover-icon.tsx +34 -0
- package/templates/default/src/components/foundations/payment-icons/index.tsx +10 -0
- package/templates/default/src/components/foundations/payment-icons/mastercard-icon.tsx +39 -0
- package/templates/default/src/components/foundations/payment-icons/paypal-icon.tsx +45 -0
- package/templates/default/src/components/foundations/payment-icons/stripe-icon.tsx +27 -0
- package/templates/default/src/components/foundations/payment-icons/union-pay-icon.tsx +37 -0
- package/templates/default/src/components/foundations/payment-icons/visa-icon.tsx +27 -0
- package/templates/default/src/components/marketing/header-navigation/base-components/nav-menu-item.tsx +41 -0
- package/templates/default/src/components/marketing/header-navigation/components/header.tsx +245 -0
- package/templates/default/src/components/marketing/header-navigation/dropdown-header-navigation.tsx +53 -0
- package/templates/default/src/components/shared/avatar/avatar-label-group.tsx +32 -0
- package/templates/default/src/components/shared/avatar/avatar-profile-photo.tsx +84 -0
- package/templates/default/src/components/shared/avatar/avatar.tsx +131 -0
- package/templates/default/src/components/shared/avatar/base-components/avatar-add-button.tsx +33 -0
- package/templates/default/src/components/shared/avatar/base-components/avatar-company-icon.tsx +26 -0
- package/templates/default/src/components/shared/avatar/base-components/avatar-online-indicator.tsx +31 -0
- package/templates/default/src/components/shared/avatar/base-components/index.ts +4 -0
- package/templates/default/src/components/shared/avatar/base-components/verified-tick.tsx +34 -0
- package/templates/default/src/components/shared/avatar/utils.ts +12 -0
- package/templates/default/src/components/shared/badges/badge-groups.tsx +176 -0
- package/templates/default/src/components/shared/badges/badge-types.ts +264 -0
- package/templates/default/src/components/shared/badges/badges.tsx +479 -0
- package/templates/default/src/components/shared/button-group/button-group.tsx +97 -0
- package/templates/default/src/components/shared/buttons/app-store-buttons-outline.tsx +454 -0
- package/templates/default/src/components/shared/buttons/app-store-buttons.tsx +806 -0
- package/templates/default/src/components/shared/buttons/button-utility.tsx +87 -0
- package/templates/default/src/components/shared/buttons/button.tsx +284 -0
- package/templates/default/src/components/shared/buttons/close-button.tsx +39 -0
- package/templates/default/src/components/shared/buttons/social-button.tsx +135 -0
- package/templates/default/src/components/shared/buttons/social-logos.tsx +115 -0
- package/templates/default/src/components/shared/checkbox/checkbox.tsx +120 -0
- package/templates/default/src/components/shared/dropdown/dropdown.tsx +138 -0
- package/templates/default/src/components/shared/input-dropdown/combobox.tsx +161 -0
- package/templates/default/src/components/shared/input-dropdown/dropdown-item.tsx +98 -0
- package/templates/default/src/components/shared/input-dropdown/input-dropdown.tsx +172 -0
- package/templates/default/src/components/shared/input-dropdown/multi-select.tsx +373 -0
- package/templates/default/src/components/shared/input-dropdown/popover.tsx +36 -0
- package/templates/default/src/components/shared/input-dropdown/select.tsx +63 -0
- package/templates/default/src/components/shared/inputs/file-upload-trigger.tsx +74 -0
- package/templates/default/src/components/shared/inputs/form/form.tsx +10 -0
- package/templates/default/src/components/shared/inputs/hint-text.tsx +34 -0
- package/templates/default/src/components/shared/inputs/input/index.tsx +189 -0
- package/templates/default/src/components/shared/inputs/input/input-payment.tsx +134 -0
- package/templates/default/src/components/shared/inputs/input/input-with-button.tsx +69 -0
- package/templates/default/src/components/shared/inputs/input/input-with-dropdown.tsx +178 -0
- package/templates/default/src/components/shared/inputs/input/input-with-prefix.tsx +74 -0
- package/templates/default/src/components/shared/inputs/label.tsx +46 -0
- package/templates/default/src/components/shared/inputs/textarea/textarea.tsx +82 -0
- package/templates/default/src/components/shared/progress-indicators/progress-circles.tsx +176 -0
- package/templates/default/src/components/shared/progress-indicators/progress-indicators.tsx +86 -0
- package/templates/default/src/components/shared/progress-indicators/simple-circle.tsx +29 -0
- package/templates/default/src/components/shared/radio-buttons/radio-buttons.tsx +125 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-avatar.tsx +62 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-checkbox.tsx +72 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-icon-card.tsx +95 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-icon-simple.tsx +70 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-payment-icon.tsx +71 -0
- package/templates/default/src/components/shared/radio-groups/radio-group-radio-button.tsx +76 -0
- package/templates/default/src/components/shared/radio-groups/radio-groups.tsx +8 -0
- package/templates/default/src/components/shared/slider/slider.tsx +76 -0
- package/templates/default/src/components/shared/tags/base-components/tag-checkbox.tsx +47 -0
- package/templates/default/src/components/shared/tags/base-components/tag-close-x.tsx +34 -0
- package/templates/default/src/components/shared/tags/tags.tsx +162 -0
- package/templates/default/src/components/shared/toggle/toggle.tsx +140 -0
- package/templates/default/src/components/shared/tooltips/tooltips.tsx +140 -0
- package/templates/default/src/components/utils/index.ts +48 -0
- package/templates/default/src/components/utils/isDeepEqual.ts +31 -0
- package/templates/default/src/components/utils/isReactComponent.ts +22 -0
- package/templates/default/src/components/utils/mergeRefs.ts +19 -0
- package/templates/default/src/components/utils/useBreakpoint.ts +36 -0
- package/templates/default/src/components/utils/uuid.ts +9 -0
- package/templates/default/src/fonts/GeistMonoVF.woff +0 -0
- package/templates/default/src/fonts/GeistVF.woff +0 -0
- package/templates/default/src/hooks/use-resize-observer.tsx +55 -0
- package/templates/default/src/providers/theme.tsx +11 -0
- package/templates/default/src/styles/colors.css +805 -0
- package/templates/default/src/styles/globals.css +86 -0
- package/templates/default/src/styles/text-styles.css +177 -0
- package/templates/default/src/styles/theme.css +1310 -0
- package/templates/default/src/styles/typography.css +428 -0
- package/templates/default/tsconfig.json +27 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
37
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
38
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
39
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
40
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
41
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
42
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
exports.program = void 0;
|
|
50
|
+
const async_retry_1 = __importDefault(require("async-retry"));
|
|
51
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
52
|
+
const commander_1 = require("commander");
|
|
53
|
+
const execa_1 = require("execa");
|
|
54
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
55
|
+
const fs_1 = __importDefault(require("fs"));
|
|
56
|
+
const ora_1 = __importDefault(require("ora"));
|
|
57
|
+
const os_1 = __importDefault(require("os"));
|
|
58
|
+
const path = __importStar(require("path"));
|
|
59
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
60
|
+
const ts_morph_1 = require("ts-morph");
|
|
61
|
+
const download_tar_api_1 = require("../helper/download-tar-api");
|
|
62
|
+
const find_css_file_1 = require("../helper/find-css-file");
|
|
63
|
+
const get_config_1 = require("../helper/get-config");
|
|
64
|
+
const get_package_info_1 = require("../helper/get-package-info");
|
|
65
|
+
const get_pkg_manager_1 = require("../helper/get-pkg-manager");
|
|
66
|
+
const get_project_1 = require("../helper/get-project");
|
|
67
|
+
const install_template_1 = require("../helper/install-template");
|
|
68
|
+
const update_color_css_1 = require("../helper/update-color-css");
|
|
69
|
+
const CONFIG_DIR = path.join(os_1.default.homedir(), ".untitledui");
|
|
70
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
71
|
+
const DEFAULT_TEMPLATE = "default";
|
|
72
|
+
const PRIVATE_TEMPLATES = ["with-stripe", "otp", "magic-link"];
|
|
73
|
+
// Directory where the project will be initialized
|
|
74
|
+
let projectPath = "";
|
|
75
|
+
let promptOptions = {
|
|
76
|
+
template: "",
|
|
77
|
+
color: "",
|
|
78
|
+
};
|
|
79
|
+
if (fs_1.default.existsSync(CONFIG_PATH)) {
|
|
80
|
+
const config = JSON.parse(fs_1.default.readFileSync(CONFIG_PATH, "utf-8"));
|
|
81
|
+
promptOptions.license = config.license;
|
|
82
|
+
}
|
|
83
|
+
const onPromptState = (state) => {
|
|
84
|
+
if (state.aborted) {
|
|
85
|
+
// If we don't re-enable the terminal cursor before exiting
|
|
86
|
+
// the program, the cursor will remain hidden
|
|
87
|
+
process.stdout.write("\x1B[?25h");
|
|
88
|
+
process.stdout.write("\n");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
exports.program = new commander_1.Command()
|
|
93
|
+
.name("init")
|
|
94
|
+
.description("initialize a new project")
|
|
95
|
+
.argument("[directory]")
|
|
96
|
+
.usage("[directory] [options]")
|
|
97
|
+
.helpOption("-h, --help", "Display this help message.")
|
|
98
|
+
.option("-t, --template <starter-kit>", "Specify a template for the project.")
|
|
99
|
+
.option("-c, --color <color-name>", "Specify a color for the project.")
|
|
100
|
+
.option("-o, --overwrite", "Overwrite existing files.", false)
|
|
101
|
+
.option("-l, --license <license-key>", "Add a license key to download the repository.")
|
|
102
|
+
.action((name, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
103
|
+
if (name) {
|
|
104
|
+
projectPath = name;
|
|
105
|
+
}
|
|
106
|
+
if (options) {
|
|
107
|
+
promptOptions.color = options.color;
|
|
108
|
+
promptOptions.template = options.template;
|
|
109
|
+
promptOptions.overwrite = options.overwrite;
|
|
110
|
+
promptOptions.license = options.license || promptOptions.license;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
yield run(options);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
console.error(chalk_1.default.red(e));
|
|
117
|
+
}
|
|
118
|
+
}));
|
|
119
|
+
function run(opts) {
|
|
120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
const cwd = process.cwd();
|
|
123
|
+
const isExistingProject = fs_1.default.existsSync(path.resolve(cwd, "package.json"));
|
|
124
|
+
// Src dir in main repo where styles and plugins folder are located
|
|
125
|
+
const stylesFolder = path.join(path.resolve(__dirname, "../../../../"));
|
|
126
|
+
// Get `theme.css` file from the src/styles directory
|
|
127
|
+
const cssFilePath = (0, find_css_file_1.findCssFile)(stylesFolder);
|
|
128
|
+
// Extract color variables from the theme.css file
|
|
129
|
+
const colors = (0, update_color_css_1.extractColorVariables)(cssFilePath !== null && cssFilePath !== void 0 ? cssFilePath : "");
|
|
130
|
+
// Get unique prefixes from the color variables
|
|
131
|
+
const prefixes = Array.from(new Set(Object.keys(colors).map((varName) => varName.split("--color-")[1].replace(/-\d{1,3}/, ""))));
|
|
132
|
+
const spinner = (0, ora_1.default)().start();
|
|
133
|
+
// Get the project configuration and check if it is a Next.js project
|
|
134
|
+
const info = yield (0, get_project_1.getNextjsProjectConfig)(cwd);
|
|
135
|
+
if (promptOptions.license) {
|
|
136
|
+
const isValidKey = yield (0, download_tar_api_1.checkLicenseKey)(promptOptions.license);
|
|
137
|
+
if (!isValidKey) {
|
|
138
|
+
spinner.fail("Invalid license key");
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
// Save the license key to the config file
|
|
142
|
+
if (!fs_1.default.existsSync(CONFIG_PATH)) {
|
|
143
|
+
const dirs = path.dirname(CONFIG_PATH);
|
|
144
|
+
fs_1.default.mkdirSync(dirs, { recursive: true });
|
|
145
|
+
fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify({ license: promptOptions.license }, null, 2));
|
|
146
|
+
}
|
|
147
|
+
const config = JSON.parse(fs_1.default.readFileSync(CONFIG_PATH, "utf-8"));
|
|
148
|
+
if (config.license !== promptOptions.license) {
|
|
149
|
+
fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify({ license: promptOptions.license }, null, 2));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!isExistingProject) {
|
|
153
|
+
spinner.stop();
|
|
154
|
+
// If user didn't provide a project name, ask for it
|
|
155
|
+
if (!projectPath) {
|
|
156
|
+
const res = yield (0, prompts_1.default)({
|
|
157
|
+
onState: onPromptState,
|
|
158
|
+
type: "text",
|
|
159
|
+
name: "path",
|
|
160
|
+
message: "What is your project named?",
|
|
161
|
+
initial: "untitled-ui",
|
|
162
|
+
});
|
|
163
|
+
if (typeof res.path === "string") {
|
|
164
|
+
projectPath = res.path.trim();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// If the directory with the project name already exists,
|
|
168
|
+
// show an error message
|
|
169
|
+
if (fs_1.default.existsSync(path.resolve(projectPath))) {
|
|
170
|
+
spinner.fail(chalk_1.default.red("Directory already exists!"));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
// If user didn't provide a template kit to start with, ask for it
|
|
174
|
+
if (!promptOptions.template) {
|
|
175
|
+
const res = yield (0, prompts_1.default)({
|
|
176
|
+
type: "select",
|
|
177
|
+
name: "template",
|
|
178
|
+
onState: onPromptState,
|
|
179
|
+
message: `Which ${chalk_1.default.cyan("starter kit")} would you like to use?`,
|
|
180
|
+
choices: [
|
|
181
|
+
{
|
|
182
|
+
title: "default-template",
|
|
183
|
+
value: DEFAULT_TEMPLATE,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: "basic-form",
|
|
187
|
+
value: "basic-form",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
title: "magic-link",
|
|
191
|
+
value: "magic-link",
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
title: "next-intl",
|
|
195
|
+
value: "next-intl",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
title: "otp",
|
|
199
|
+
value: "otp",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
title: "react-hook-form",
|
|
203
|
+
value: "react-hook-form",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
title: "with-stripe",
|
|
207
|
+
value: "with-stripe",
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
});
|
|
211
|
+
promptOptions.template = res.template;
|
|
212
|
+
if (PRIVATE_TEMPLATES.includes(promptOptions.template) && !promptOptions.license) {
|
|
213
|
+
const res = yield (0, prompts_1.default)({
|
|
214
|
+
type: "text",
|
|
215
|
+
name: "license",
|
|
216
|
+
onState: onPromptState,
|
|
217
|
+
message: `Enter the license key to download the ${chalk_1.default.cyan(promptOptions.template)} template:`,
|
|
218
|
+
});
|
|
219
|
+
promptOptions.license = res.license;
|
|
220
|
+
const isValidKey = yield (0, download_tar_api_1.checkLicenseKey)(res.license);
|
|
221
|
+
if (!isValidKey) {
|
|
222
|
+
spinner.fail("Invalid license key");
|
|
223
|
+
process.exit(0);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
spinner.succeed("Template is selected: " + chalk_1.default.green(promptOptions.template));
|
|
228
|
+
// If project exists, but it's not a Next.js project, show an error message
|
|
229
|
+
}
|
|
230
|
+
else if ((info === null || info === void 0 ? void 0 : info.framework) === "other") {
|
|
231
|
+
spinner.fail("Unsupported project framework");
|
|
232
|
+
console.log(`Please refer to the documentation ${chalk_1.default.cyan("https://untitled.xyz/docs")} for supported frameworks or proceed with manual installation.`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
spinner.succeed(chalk_1.default.yellow("Detected Next.js project, proceeding with the setup..."));
|
|
237
|
+
}
|
|
238
|
+
// If user didn't provide a color, ask for it
|
|
239
|
+
if (!promptOptions.color) {
|
|
240
|
+
const res = yield (0, prompts_1.default)({
|
|
241
|
+
type: "select",
|
|
242
|
+
name: "color",
|
|
243
|
+
onState: onPromptState,
|
|
244
|
+
initial: (_a = opts.color) !== null && _a !== void 0 ? _a : "",
|
|
245
|
+
message: `Which ${chalk_1.default.cyan("color")} would you like to use as the ${chalk_1.default.cyanBright("brand")} color?`,
|
|
246
|
+
choices: prefixes.map((prefix) => ({
|
|
247
|
+
title: prefix,
|
|
248
|
+
value: prefix,
|
|
249
|
+
})),
|
|
250
|
+
});
|
|
251
|
+
promptOptions.color = res.color;
|
|
252
|
+
}
|
|
253
|
+
// If the project is not an existing project, download the starter kit
|
|
254
|
+
if (projectPath && !isExistingProject) {
|
|
255
|
+
const appPath = path.resolve(projectPath);
|
|
256
|
+
console.log(`\nCreating a new project in ${chalk_1.default.blue(projectPath)}`);
|
|
257
|
+
const spinner = (0, ora_1.default)("Downloading and extracting the repository...").start();
|
|
258
|
+
try {
|
|
259
|
+
// Create the project directory
|
|
260
|
+
fs_1.default.mkdirSync(appPath, { recursive: true });
|
|
261
|
+
if (promptOptions.template === DEFAULT_TEMPLATE) {
|
|
262
|
+
// Template folder path
|
|
263
|
+
const templatePath = path.resolve(path.join(__dirname, "../../templates/", promptOptions.template));
|
|
264
|
+
// Copy the template files to the project directory
|
|
265
|
+
(0, install_template_1.copyTemplateFiles)(templatePath, appPath);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Download and extract the repository, retry 2 times before failing
|
|
269
|
+
// Always use the API-based download for both public and private repositories
|
|
270
|
+
yield (0, async_retry_1.default)(() => (0, download_tar_api_1.downloadAndExtractRepoFromApi)(appPath, {
|
|
271
|
+
username: "a-peak-works",
|
|
272
|
+
repo: "starter-kits",
|
|
273
|
+
branch: "master",
|
|
274
|
+
template: promptOptions.template,
|
|
275
|
+
key: promptOptions.license,
|
|
276
|
+
}), {
|
|
277
|
+
retries: 2,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
spinner.succeed("Files are downloaded and extracted successfully!");
|
|
281
|
+
const dependencies = (0, ora_1.default)({ text: "Installing dependencies..." }).start();
|
|
282
|
+
// Update the theme.css file with the selected color
|
|
283
|
+
// Starter kits always have the theme.css file in the
|
|
284
|
+
// src/styles directory
|
|
285
|
+
const newCssFilePath = fast_glob_1.default.sync(["**/styles/theme.css"], { cwd: appPath, absolute: true, onlyFiles: true })[0];
|
|
286
|
+
(0, update_color_css_1.updateCssFile)("brand", promptOptions.color, newCssFilePath);
|
|
287
|
+
// Install dependencies and initialize git, retry once if there is a peer dependency conflict
|
|
288
|
+
yield (0, async_retry_1.default)(() => (0, execa_1.execa)("sh", ["-c", `cd ${projectPath} && ${(0, get_pkg_manager_1.getPkgManager)()} install && git init`]).catch((e) => __awaiter(this, void 0, void 0, function* () {
|
|
289
|
+
if (e.message.includes("peer")) {
|
|
290
|
+
dependencies.warn("Dependency conflict detected. Retrying with --legacy-peer-deps...");
|
|
291
|
+
dependencies.start("Installing dependencies with --legacy-peer-deps flag");
|
|
292
|
+
// Retry with the --legacy-peer-deps flag
|
|
293
|
+
yield (0, execa_1.execa)("sh", [
|
|
294
|
+
"-c",
|
|
295
|
+
`cd ${projectPath} && ${(0, get_pkg_manager_1.getPkgManager)() === "npm" ? "npm --legacy-peer-deps" : (0, get_pkg_manager_1.getPkgManager)()} install && git init`,
|
|
296
|
+
]);
|
|
297
|
+
}
|
|
298
|
+
})), {
|
|
299
|
+
retries: 1,
|
|
300
|
+
});
|
|
301
|
+
dependencies.succeed("Dependencies installed");
|
|
302
|
+
console.log(`\nYour project is ready, to get staretd run the following commands:\n\n cd ${chalk_1.default.cyan(projectPath)}\n ${chalk_1.default.cyan((0, get_pkg_manager_1.getPkgManager)())} run dev`);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
spinner.fail(chalk_1.default.red("\nFailed to download and extract the repository"));
|
|
307
|
+
// If there is an error, show the error message and exit the process
|
|
308
|
+
if (error instanceof Error) {
|
|
309
|
+
console.error(error.message);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.error("\n");
|
|
313
|
+
}
|
|
314
|
+
// Remove the project directory if the download and extraction fails
|
|
315
|
+
fs_1.default.rmdirSync(appPath, { recursive: true });
|
|
316
|
+
process.exit(0);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
const existingFiles = [];
|
|
321
|
+
const configFiles = (0, get_config_1.resolveConfigPaths)(cwd);
|
|
322
|
+
// Src dir in main repo where styles and plugins folder are located
|
|
323
|
+
const srcDir = path.join(path.resolve(__dirname, "../../../../"));
|
|
324
|
+
// Get all the files in the styles, plugins and public/fonts directories
|
|
325
|
+
const styleFiles = fast_glob_1.default.sync(["**/{styles,plugins}/**", "postcss.config.*", "**/public/fonts/**"], {
|
|
326
|
+
cwd: srcDir,
|
|
327
|
+
onlyFiles: true,
|
|
328
|
+
ignore: get_project_1.PROJECT_SHARED_IGNORE.filter((ignore) => !ignore.includes("public")),
|
|
329
|
+
});
|
|
330
|
+
// Get dependencies from the package.json file in the main repo
|
|
331
|
+
// and with the specified versions
|
|
332
|
+
const dependencies = (0, get_package_info_1.getDependenciesFromPackageJson)({
|
|
333
|
+
cwd: srcDir,
|
|
334
|
+
dependencies: [
|
|
335
|
+
"tailwindcss",
|
|
336
|
+
"tailwindcss-animate",
|
|
337
|
+
"@tailwindcss/typography",
|
|
338
|
+
"tailwindcss-react-aria-components",
|
|
339
|
+
"@designbycode/tailwindcss-mask-image",
|
|
340
|
+
],
|
|
341
|
+
devDependencies: ["@tailwindcss/postcss", "postcss"],
|
|
342
|
+
});
|
|
343
|
+
styleFiles.forEach((file) => {
|
|
344
|
+
// Filter out postcss and font files as they are one level above
|
|
345
|
+
// the src directory `root`/ and public/
|
|
346
|
+
const isPostCSSOrFont = file.includes("postcss.config") || file.includes("fonts");
|
|
347
|
+
const newFile = path.resolve(process.cwd(), isPostCSSOrFont ? file : `${(info === null || info === void 0 ? void 0 : info.isSrcDir) ? "src" : ""}/${file}`);
|
|
348
|
+
if (fs_1.default.existsSync(newFile)) {
|
|
349
|
+
// Overwrite public/fonts files or if the user has specified to overwrite
|
|
350
|
+
if (newFile.includes("public/fonts") || (promptOptions === null || promptOptions === void 0 ? void 0 : promptOptions.overwrite)) {
|
|
351
|
+
fs_1.default.copyFileSync(path.resolve(srcDir, file), newFile);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
existingFiles.push(path.relative(process.cwd(), newFile));
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// Create the directory if it doesn't exist
|
|
359
|
+
fs_1.default.mkdirSync(path.dirname(newFile), { recursive: true });
|
|
360
|
+
// Create an empty file
|
|
361
|
+
fs_1.default.writeFileSync(newFile, "");
|
|
362
|
+
// Copy the file from the main repo to the project directory
|
|
363
|
+
fs_1.default.copyFileSync(path.resolve(srcDir, file), newFile);
|
|
364
|
+
});
|
|
365
|
+
// If the files already exist in the project directory, show the user
|
|
366
|
+
// which files exist
|
|
367
|
+
if (existingFiles.length && !(promptOptions === null || promptOptions === void 0 ? void 0 : promptOptions.overwrite)) {
|
|
368
|
+
console.log("\n");
|
|
369
|
+
spinner.fail(`Following files already exist in the directory. Use ${chalk_1.default.cyan("--overwrite")} or ${chalk_1.default.cyan("-o")} to overwrite existing files, or refer to the documentation ${chalk_1.default.cyan("https://untitled.xyz/docs")} for manual installation.`);
|
|
370
|
+
existingFiles.forEach((file) => {
|
|
371
|
+
console.log(`- ${chalk_1.default.green(file)}`);
|
|
372
|
+
});
|
|
373
|
+
process.exit(0);
|
|
374
|
+
}
|
|
375
|
+
// If tailwind config file exists, show the user how to add it to the globals.css file
|
|
376
|
+
if (configFiles === null || configFiles === void 0 ? void 0 : configFiles.tailwindFile) {
|
|
377
|
+
console.log("\nTailwind config file exists in the project directory. You can add it to your globals.css as follows:");
|
|
378
|
+
console.log(`\n${chalk_1.default.cyan(`@config "../${(info === null || info === void 0 ? void 0 : info.isSrcDir) && "../"}${path.relative(process.cwd(), configFiles.tailwindFile)}";`)}\n`);
|
|
379
|
+
}
|
|
380
|
+
// Main file in the project directory, it's either layout.tsx or _app.tsx
|
|
381
|
+
const mainFile = (configFiles === null || configFiles === void 0 ? void 0 : configFiles.layoutFile) || (configFiles === null || configFiles === void 0 ? void 0 : configFiles.appFile) || "";
|
|
382
|
+
// Create a new project instance with the tsconfig file
|
|
383
|
+
const project = new ts_morph_1.Project({
|
|
384
|
+
tsConfigFilePath: path.resolve((configFiles === null || configFiles === void 0 ? void 0 : configFiles.tsConfig) || ""),
|
|
385
|
+
});
|
|
386
|
+
const sourceFile = project.addSourceFileAtPath(path.resolve(mainFile));
|
|
387
|
+
// Remove the existing import declarations for the style files
|
|
388
|
+
// to avoid conflicts when updating the alias pathes
|
|
389
|
+
const stylesToRemove = ["colors.css", "globals.css", "inter.css", "text-styles.css", "theme.css", "typography.css"];
|
|
390
|
+
// If style files already exist, remove them to avoid conflicts
|
|
391
|
+
// when updating alias pathes
|
|
392
|
+
sourceFile
|
|
393
|
+
.getImportDeclarations()
|
|
394
|
+
.filter((importDeclaration) => stylesToRemove.includes(importDeclaration.getModuleSpecifierValue()))
|
|
395
|
+
.forEach((importDeclaration) => importDeclaration.remove());
|
|
396
|
+
//If not src alis path is used, we will update it to the correct path
|
|
397
|
+
// using dots
|
|
398
|
+
const pathsDeep = path.relative(path.resolve(process.cwd(), `${(info === null || info === void 0 ? void 0 : info.isSrcDir) && "src"}`), mainFile).split("/").length;
|
|
399
|
+
// Add the import declarations for the style files with the
|
|
400
|
+
// updated alias pathes
|
|
401
|
+
sourceFile.addImportDeclarations(styleFiles
|
|
402
|
+
.filter((file) => file.includes("styles"))
|
|
403
|
+
.map((file) => {
|
|
404
|
+
var _a, _b, _c;
|
|
405
|
+
return ({
|
|
406
|
+
moduleSpecifier: `${((_a = info === null || info === void 0 ? void 0 : info.aliasPrefix) === null || _a === void 0 ? void 0 : _a.stylesPrefix) || ((_b = info === null || info === void 0 ? void 0 : info.aliasPrefix) === null || _b === void 0 ? void 0 : _b.srcPrefix) || "../".repeat(pathsDeep - 1)}${((_c = info === null || info === void 0 ? void 0 : info.aliasPrefix) === null || _c === void 0 ? void 0 : _c.stylesPrefix) ? file === null || file === void 0 ? void 0 : file.split("styles/")[1] : file}`,
|
|
407
|
+
});
|
|
408
|
+
}));
|
|
409
|
+
// Save the source file
|
|
410
|
+
sourceFile.saveSync();
|
|
411
|
+
const dependencySpinner = (0, ora_1.default)();
|
|
412
|
+
// Get the theme.css file from the project directory
|
|
413
|
+
const themeCssFile = fast_glob_1.default.sync(["**/styles/theme.css"], { cwd, absolute: true, onlyFiles: true, ignore: get_project_1.PROJECT_SHARED_IGNORE });
|
|
414
|
+
// If the theme.css file doesn't exist, show an error message
|
|
415
|
+
if (!(themeCssFile === null || themeCssFile === void 0 ? void 0 : themeCssFile.length))
|
|
416
|
+
return spinner.fail("Failed to copy theme.css file");
|
|
417
|
+
// Update the theme.css file with the selected color
|
|
418
|
+
(0, update_color_css_1.updateCssFile)("brand", promptOptions.color, (_b = themeCssFile[0]) !== null && _b !== void 0 ? _b : "");
|
|
419
|
+
// Install dependencies from the package.json file in the main repo
|
|
420
|
+
if (!dependencies) {
|
|
421
|
+
dependencySpinner.fail("Failed to get dependencies from package.json");
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
dependencySpinner.start("Installing dependencies");
|
|
425
|
+
// Run the package manager install command to install the dependencies
|
|
426
|
+
// and devDependencies
|
|
427
|
+
yield (0, execa_1.execa)((0, get_pkg_manager_1.getPkgManager)(), [(0, get_pkg_manager_1.getPkgManager)() === "npm" ? "install" : "add", ...dependencies.dependencies], {});
|
|
428
|
+
yield (0, execa_1.execa)((0, get_pkg_manager_1.getPkgManager)(), [(0, get_pkg_manager_1.getPkgManager)() === "npm" ? "install" : "add", "-D", ...dependencies.devDependencies], {});
|
|
429
|
+
dependencySpinner.succeed("Dependencies installed");
|
|
430
|
+
spinner.succeed(chalk_1.default.green("Files are extracted successfully!"));
|
|
431
|
+
console.log("\nYour project is ready, you can now start adding components.");
|
|
432
|
+
// Exit the process with a success status code
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.downloadAndExtractRepoFromApi = downloadAndExtractRepoFromApi;
|
|
16
|
+
exports.downloadTarStream = downloadTarStream;
|
|
17
|
+
exports.checkLicenseKey = checkLicenseKey;
|
|
18
|
+
const node_path_1 = require("node:path");
|
|
19
|
+
const node_stream_1 = require("node:stream");
|
|
20
|
+
const promises_1 = require("node:stream/promises");
|
|
21
|
+
const tar_1 = require("tar");
|
|
22
|
+
const config_json_1 = __importDefault(require("../res/config.json"));
|
|
23
|
+
/**
|
|
24
|
+
* Downloads and extracts the tarball from the returned tarball stream
|
|
25
|
+
* @param root - The main root directory where the tarball should be extracted
|
|
26
|
+
* @param info - The repository information required for downloading the tarball
|
|
27
|
+
*/
|
|
28
|
+
function downloadAndExtractRepoFromApi(root, info) {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
try {
|
|
31
|
+
// Convert the web ReadableStream to a Node.js ReadableStream
|
|
32
|
+
const stream = yield downloadTarStream(info);
|
|
33
|
+
yield (0, promises_1.pipeline)(stream, (0, tar_1.x)({
|
|
34
|
+
cwd: root, // directory to extract files into
|
|
35
|
+
strip: 2, // how many path segments to remove (depends on the tar structure)
|
|
36
|
+
filter: (p) => {
|
|
37
|
+
// Normalize paths to POSIX format for consistency
|
|
38
|
+
const posixPath = p.split(node_path_1.sep).join(node_path_1.posix.sep);
|
|
39
|
+
// Extract only files that include the specified template name
|
|
40
|
+
return posixPath.includes(info.template || "basic-form");
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof Error) {
|
|
46
|
+
// Provide more context about the error
|
|
47
|
+
throw new Error(`Failed to download or extract repository from API: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Fetches the tarball from api endpoint and returns a readable stream of the tarball contents.
|
|
55
|
+
* Works for both public and private repositories, using a license key when provided.
|
|
56
|
+
*
|
|
57
|
+
* @param info - The repository information required for downloading the tarball.
|
|
58
|
+
* @returns A readable stream of the tarball contents.
|
|
59
|
+
* @throws Will throw an error if the fetch request fails or if there is no response body.
|
|
60
|
+
*/
|
|
61
|
+
function downloadTarStream(info) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
// Construct the endpoint with the license
|
|
64
|
+
const apiUrl = `${config_json_1.default.api_url}/download-repo`;
|
|
65
|
+
try {
|
|
66
|
+
// Create a copy of the info to send to the API
|
|
67
|
+
const requestInfo = Object.assign({}, info);
|
|
68
|
+
// Fetch the tar.gz from the server's /download route
|
|
69
|
+
const response = yield fetch(apiUrl, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
Accept: "application/octet-stream",
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify(requestInfo),
|
|
76
|
+
});
|
|
77
|
+
// Throw an error if authentication failed (only relevant when a license key is provided)
|
|
78
|
+
if (response.status === 403 || response.status === 404) {
|
|
79
|
+
throw new Error(info.key ? "License key is invalid or expired" : "Repository not found");
|
|
80
|
+
}
|
|
81
|
+
// Throw an error if the response isn't OK
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
throw new Error(`Failed to download from API. Status: ${response.status} ${response.statusText}`);
|
|
84
|
+
}
|
|
85
|
+
// Throw an error if there's no body
|
|
86
|
+
if (!response.body) {
|
|
87
|
+
throw new Error("Response body is empty");
|
|
88
|
+
}
|
|
89
|
+
// Verify content type if available
|
|
90
|
+
const contentType = response.headers.get("content-type");
|
|
91
|
+
if (contentType &&
|
|
92
|
+
!contentType.includes("application/x-gzip") &&
|
|
93
|
+
!contentType.includes("application/octet-stream") &&
|
|
94
|
+
!contentType.includes("application/tar+gzip")) {
|
|
95
|
+
console.warn(`Warning: Unexpected content type: ${contentType}. Expected tar/gzip related content.`);
|
|
96
|
+
}
|
|
97
|
+
// Convert the web ReadableStream to a Node.js ReadableStream
|
|
98
|
+
return node_stream_1.Readable.fromWeb(response.body);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error instanceof Error) {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
throw new Error("Unknown error occurred while downloading the tarball");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Checks if the license key is valid by sending a request to the server.
|
|
110
|
+
*
|
|
111
|
+
* @param key - The license key to be validated by the server
|
|
112
|
+
* @returns A boolean indicating whether the license key is valid
|
|
113
|
+
*/
|
|
114
|
+
function checkLicenseKey(key) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
const apiUrl = `${config_json_1.default.api_url}/validate-key?key=${key}`;
|
|
117
|
+
try {
|
|
118
|
+
// Fetch the tar.gz from the server's /download route
|
|
119
|
+
const response = yield fetch(apiUrl);
|
|
120
|
+
if (response.status !== 200) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.downloadAndExtractRepo = downloadAndExtractRepo;
|
|
13
|
+
exports.downloadTarStream = downloadTarStream;
|
|
14
|
+
const node_path_1 = require("node:path");
|
|
15
|
+
const node_stream_1 = require("node:stream");
|
|
16
|
+
const promises_1 = require("node:stream/promises");
|
|
17
|
+
const tar_1 = require("tar");
|
|
18
|
+
/**
|
|
19
|
+
* Downloads and extracts a GitHub repository tarball to the specified directory.
|
|
20
|
+
*
|
|
21
|
+
* @param root - The local directory where the repository should be extracted.
|
|
22
|
+
* @param repoInfo - An object containing repository details such as username, name, and branch.
|
|
23
|
+
* @throws Will throw an error if the download fails.
|
|
24
|
+
*/
|
|
25
|
+
function downloadAndExtractRepo(root_1, _a) {
|
|
26
|
+
return __awaiter(this, arguments, void 0, function* (root, { username, repo, branch, template = "basic-form" }) {
|
|
27
|
+
try {
|
|
28
|
+
const url = `https://codeload.github.com/${username}/${repo}/tar.gz/${branch}`;
|
|
29
|
+
const stream = yield downloadTarStream(url);
|
|
30
|
+
yield (0, promises_1.pipeline)(
|
|
31
|
+
// Fetch and stream the tar.gz archive from GitHub
|
|
32
|
+
stream,
|
|
33
|
+
// Extract only the necessary files matching the template name
|
|
34
|
+
(0, tar_1.x)({
|
|
35
|
+
cwd: root, // Extract into the specified root directory
|
|
36
|
+
strip: 2, // Remove first two path segments to keep only relevant files
|
|
37
|
+
filter: (p) => {
|
|
38
|
+
// Normalize paths to POSIX format for consistency
|
|
39
|
+
const posixPath = p.split(node_path_1.sep).join(node_path_1.posix.sep);
|
|
40
|
+
// Extract only files that include the specified template name
|
|
41
|
+
return posixPath.includes(template);
|
|
42
|
+
},
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof Error) {
|
|
47
|
+
// Provide more context about the error
|
|
48
|
+
throw new Error(`Failed to download or extract repository: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Downloads a repository tarball as a readable stream from a given URL.
|
|
56
|
+
*
|
|
57
|
+
* @param url - The URL to the tarball file.
|
|
58
|
+
* @returns A readable stream of the tarball contents.
|
|
59
|
+
* @throws Will throw an error if the fetch request fails or if there is no response body.
|
|
60
|
+
*/
|
|
61
|
+
function downloadTarStream(url) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
// Fetch the tarball file from GitHub
|
|
64
|
+
const res = yield fetch(url);
|
|
65
|
+
// Check if the response is successful
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new Error(`Failed to download: ${url} - Status: ${res.status} ${res.statusText}`);
|
|
68
|
+
}
|
|
69
|
+
// Ensure the response body exists before proceeding
|
|
70
|
+
if (!res.body) {
|
|
71
|
+
throw new Error(`Failed to download: ${url} - No response body`);
|
|
72
|
+
}
|
|
73
|
+
// Verify content type if available
|
|
74
|
+
const contentType = res.headers.get("content-type");
|
|
75
|
+
if (contentType && !contentType.includes("application/x-gzip") && !contentType.includes("application/octet-stream")) {
|
|
76
|
+
console.warn(`Warning: Unexpected content type: ${contentType}. Expected application/x-gzip or application/octet-stream.`);
|
|
77
|
+
}
|
|
78
|
+
// Convert the web ReadableStream to a Node.js ReadableStream
|
|
79
|
+
return node_stream_1.Readable.fromWeb(res.body);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findCssFile = findCssFile;
|
|
7
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
8
|
+
const get_project_1 = require("./get-project");
|
|
9
|
+
/**
|
|
10
|
+
* Searches for a CSS file named `theme.css` in the project directory and
|
|
11
|
+
* returns it.
|
|
12
|
+
*
|
|
13
|
+
* @param cwd - The current working directory where the search should begin.
|
|
14
|
+
* @returns The absolute path of the `theme.css` file if found, otherwise `null`.
|
|
15
|
+
*/
|
|
16
|
+
function findCssFile(cwd) {
|
|
17
|
+
const files = fast_glob_1.default.sync("**/**/theme.css", { onlyFiles: true, absolute: true, cwd, ignore: get_project_1.PROJECT_SHARED_IGNORE });
|
|
18
|
+
return files.length ? files[0] : null;
|
|
19
|
+
}
|