tailar 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +183 -0
- package/README.npm.md +183 -0
- package/dist/api/client.d.ts +47 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +329 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth/browser.d.ts +11 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +46 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/flow.d.ts +28 -0
- package/dist/auth/flow.d.ts.map +1 -0
- package/dist/auth/flow.js +171 -0
- package/dist/auth/flow.js.map +1 -0
- package/dist/auth/storage.d.ts +30 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +112 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/commands/add.d.ts +8 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +285 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +230 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +8 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +176 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/installers/dependencies.d.ts +27 -0
- package/dist/installers/dependencies.d.ts.map +1 -0
- package/dist/installers/dependencies.js +185 -0
- package/dist/installers/dependencies.js.map +1 -0
- package/dist/installers/files.d.ts +50 -0
- package/dist/installers/files.d.ts.map +1 -0
- package/dist/installers/files.js +211 -0
- package/dist/installers/files.js.map +1 -0
- package/dist/installers/install-feature.d.ts +20 -0
- package/dist/installers/install-feature.d.ts.map +1 -0
- package/dist/installers/install-feature.js +169 -0
- package/dist/installers/install-feature.js.map +1 -0
- package/dist/installers/post-install.d.ts +18 -0
- package/dist/installers/post-install.d.ts.map +1 -0
- package/dist/installers/post-install.js +228 -0
- package/dist/installers/post-install.js.map +1 -0
- package/dist/installers/templates.d.ts +22 -0
- package/dist/installers/templates.d.ts.map +1 -0
- package/dist/installers/templates.js +62 -0
- package/dist/installers/templates.js.map +1 -0
- package/dist/registry/loader.d.ts +21 -0
- package/dist/registry/loader.d.ts.map +1 -0
- package/dist/registry/loader.js +83 -0
- package/dist/registry/loader.js.map +1 -0
- package/dist/registry/query.d.ts +55 -0
- package/dist/registry/query.d.ts.map +1 -0
- package/dist/registry/query.js +123 -0
- package/dist/registry/query.js.map +1 -0
- package/dist/types/config.d.ts +85 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/registry.d.ts +180 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/registry.js +8 -0
- package/dist/types/registry.js.map +1 -0
- package/dist/types/wizard.d.ts +43 -0
- package/dist/types/wizard.d.ts.map +1 -0
- package/dist/types/wizard.js +59 -0
- package/dist/types/wizard.js.map +1 -0
- package/dist/utils/clack-wizard.d.ts +9 -0
- package/dist/utils/clack-wizard.d.ts.map +1 -0
- package/dist/utils/clack-wizard.js +328 -0
- package/dist/utils/clack-wizard.js.map +1 -0
- package/dist/utils/config.d.ts +49 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +121 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +56 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +93 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/package-manager.d.ts +41 -0
- package/dist/utils/package-manager.d.ts.map +1 -0
- package/dist/utils/package-manager.js +118 -0
- package/dist/utils/package-manager.js.map +1 -0
- package/dist/utils/prompts.d.ts +22 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +142 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/validation.d.ts +50 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +108 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Manager
|
|
3
|
+
*
|
|
4
|
+
* Handles merging dependencies into package.json and running install commands.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile, writeFile } from "fs/promises";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
import { getInstallCommand } from "../utils/package-manager.js";
|
|
10
|
+
/**
|
|
11
|
+
* Read package.json
|
|
12
|
+
*/
|
|
13
|
+
async function readPackageJson(projectPath) {
|
|
14
|
+
const packagePath = join(projectPath, "package.json");
|
|
15
|
+
const content = await readFile(packagePath, "utf-8");
|
|
16
|
+
return JSON.parse(content);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Write package.json
|
|
20
|
+
*/
|
|
21
|
+
async function writePackageJson(projectPath, pkg) {
|
|
22
|
+
const packagePath = join(projectPath, "package.json");
|
|
23
|
+
const content = JSON.stringify(pkg, null, 2) + "\n";
|
|
24
|
+
await writeFile(packagePath, content, "utf-8");
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Merge dependencies into package.json
|
|
28
|
+
*/
|
|
29
|
+
export async function mergeDependencies(projectPath, dependencyMaps) {
|
|
30
|
+
const pkg = await readPackageJson(projectPath);
|
|
31
|
+
const added = {
|
|
32
|
+
dependencies: [],
|
|
33
|
+
devDependencies: [],
|
|
34
|
+
};
|
|
35
|
+
const conflicts = [];
|
|
36
|
+
// Ensure dependency objects exist
|
|
37
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
38
|
+
pkg.devDependencies = pkg.devDependencies || {};
|
|
39
|
+
// Helper to resolve version conflicts by using the higher version
|
|
40
|
+
// Only reports conflicts if versions are truly incompatible (different major versions)
|
|
41
|
+
function resolveVersionConflict(existing, incoming) {
|
|
42
|
+
if (existing === incoming) {
|
|
43
|
+
return { version: existing, isConflict: false };
|
|
44
|
+
}
|
|
45
|
+
// Extract version numbers from semver ranges (e.g., ^0.561.0 -> 0.561.0)
|
|
46
|
+
const extractVersion = (v) => {
|
|
47
|
+
// Remove range prefixes (^, ~, >=, etc.)
|
|
48
|
+
return v.replace(/^[\^~>=<]+/, "");
|
|
49
|
+
};
|
|
50
|
+
// Extract prefix (^, ~, etc.)
|
|
51
|
+
const extractPrefix = (v) => {
|
|
52
|
+
const match = v.match(/^([\^~>=<]+)/);
|
|
53
|
+
return match ? match[1] : "^";
|
|
54
|
+
};
|
|
55
|
+
const existingVersion = extractVersion(existing);
|
|
56
|
+
const incomingVersion = extractVersion(incoming);
|
|
57
|
+
const existingPrefix = extractPrefix(existing);
|
|
58
|
+
const incomingPrefix = extractPrefix(incoming);
|
|
59
|
+
// Parse version numbers for comparison (major.minor.patch)
|
|
60
|
+
const parseVersion = (v) => {
|
|
61
|
+
return v.split(".").map((n) => parseInt(n, 10) || 0);
|
|
62
|
+
};
|
|
63
|
+
const existingParts = parseVersion(existingVersion);
|
|
64
|
+
const incomingParts = parseVersion(incomingVersion);
|
|
65
|
+
// Check if versions are compatible (same major version with compatible prefixes)
|
|
66
|
+
// For ^ prefix, versions with same major are compatible
|
|
67
|
+
const sameMajor = existingParts[0] === incomingParts[0];
|
|
68
|
+
const compatiblePrefixes = (existingPrefix === "^" && incomingPrefix === "^") ||
|
|
69
|
+
(existingPrefix === "~" && incomingPrefix === "~") ||
|
|
70
|
+
existingPrefix === incomingPrefix;
|
|
71
|
+
// Compare versions part by part
|
|
72
|
+
let useIncoming = false;
|
|
73
|
+
for (let i = 0; i < Math.max(existingParts.length, incomingParts.length); i++) {
|
|
74
|
+
const existingPart = existingParts[i] || 0;
|
|
75
|
+
const incomingPart = incomingParts[i] || 0;
|
|
76
|
+
if (incomingPart > existingPart) {
|
|
77
|
+
useIncoming = true;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
else if (incomingPart < existingPart) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Use the higher version, preserving the prefix from the higher version
|
|
85
|
+
const higherVersion = useIncoming ? incoming : existing;
|
|
86
|
+
// Only report as conflict if versions are truly incompatible:
|
|
87
|
+
// - Different major versions (breaking changes)
|
|
88
|
+
// - Different prefixes that affect compatibility (^ vs ~ vs exact)
|
|
89
|
+
// For same major version with compatible prefixes, they're compatible (no conflict)
|
|
90
|
+
const isConflict = !(sameMajor && compatiblePrefixes);
|
|
91
|
+
return { version: higherVersion, isConflict };
|
|
92
|
+
}
|
|
93
|
+
// Merge all dependency maps
|
|
94
|
+
for (const depMap of dependencyMaps) {
|
|
95
|
+
// Merge dependencies
|
|
96
|
+
if (depMap.dependencies) {
|
|
97
|
+
for (const [name, version] of Object.entries(depMap.dependencies)) {
|
|
98
|
+
const existing = pkg.dependencies[name];
|
|
99
|
+
if (existing) {
|
|
100
|
+
const resolved = resolveVersionConflict(existing, version);
|
|
101
|
+
if (resolved.isConflict) {
|
|
102
|
+
conflicts.push(`${name}: ${existing} vs ${version} (using ${resolved.version})`);
|
|
103
|
+
}
|
|
104
|
+
pkg.dependencies[name] = resolved.version;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
pkg.dependencies[name] = version;
|
|
108
|
+
}
|
|
109
|
+
added.dependencies.push(name);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Merge devDependencies
|
|
113
|
+
if (depMap.devDependencies) {
|
|
114
|
+
for (const [name, version] of Object.entries(depMap.devDependencies)) {
|
|
115
|
+
const existing = pkg.devDependencies[name];
|
|
116
|
+
if (existing) {
|
|
117
|
+
const resolved = resolveVersionConflict(existing, version);
|
|
118
|
+
if (resolved.isConflict) {
|
|
119
|
+
conflicts.push(`${name}: ${existing} vs ${version} (using ${resolved.version})`);
|
|
120
|
+
}
|
|
121
|
+
pkg.devDependencies[name] = resolved.version;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
pkg.devDependencies[name] = version;
|
|
125
|
+
}
|
|
126
|
+
added.devDependencies.push(name);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Sort dependencies alphabetically
|
|
131
|
+
pkg.dependencies = sortObject(pkg.dependencies);
|
|
132
|
+
pkg.devDependencies = sortObject(pkg.devDependencies);
|
|
133
|
+
// Write updated package.json
|
|
134
|
+
await writePackageJson(projectPath, pkg);
|
|
135
|
+
return { added, conflicts };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Sort object keys alphabetically
|
|
139
|
+
*/
|
|
140
|
+
function sortObject(obj) {
|
|
141
|
+
return Object.keys(obj)
|
|
142
|
+
.sort()
|
|
143
|
+
.reduce((sorted, key) => {
|
|
144
|
+
sorted[key] = obj[key];
|
|
145
|
+
return sorted;
|
|
146
|
+
}, {});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Run package manager install
|
|
150
|
+
*/
|
|
151
|
+
export async function runInstall(projectPath, packageManager, options = {}) {
|
|
152
|
+
let command = getInstallCommand(packageManager);
|
|
153
|
+
// Add legacy peer deps flag for npm to handle version conflicts
|
|
154
|
+
if (packageManager === "npm") {
|
|
155
|
+
command += " --legacy-peer-deps";
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
execSync(command, {
|
|
159
|
+
cwd: projectPath,
|
|
160
|
+
stdio: options.silent ? "ignore" : "inherit",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
throw new Error(`Failed to run ${command}: ${error}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Collect all dependencies from entry and its variants
|
|
169
|
+
*/
|
|
170
|
+
export function collectDependencies(entry, selectedVariant) {
|
|
171
|
+
const deps = [];
|
|
172
|
+
// Add entry's base dependencies
|
|
173
|
+
if (entry.dependencies) {
|
|
174
|
+
deps.push(entry.dependencies);
|
|
175
|
+
}
|
|
176
|
+
// Add variant-specific dependencies
|
|
177
|
+
if (selectedVariant && entry.variants) {
|
|
178
|
+
const variant = entry.variants.find((v) => v.name === selectedVariant);
|
|
179
|
+
if (variant?.dependencies) {
|
|
180
|
+
deps.push(variant.dependencies);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return deps;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/installers/dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Installer
|
|
3
|
+
*
|
|
4
|
+
* Handles file installation, template substitution, and path resolution.
|
|
5
|
+
* Always uses API endpoint for fetching files.
|
|
6
|
+
*/
|
|
7
|
+
import { FileMapping, ProjectContext } from "../types/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Resolve template variables in a path
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveTemplatePath(path: string, context: ProjectContext, variables?: Record<string, string>): string;
|
|
12
|
+
/**
|
|
13
|
+
* Apply template substitution to file content
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyTemplateSubstitution(content: string, variables: Record<string, string>): string;
|
|
16
|
+
/**
|
|
17
|
+
* Merge JSON content with existing JSON file
|
|
18
|
+
*/
|
|
19
|
+
export declare function mergeJsonContent(existingContent: string, newContent: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Check if file exists at target location
|
|
22
|
+
*/
|
|
23
|
+
export declare function checkFileExists(projectPath: string, targetPath: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Install a single file
|
|
26
|
+
*/
|
|
27
|
+
export declare function installFile(sourceContent: string, projectPath: string, targetPath: string, variables?: Record<string, string>, options?: {
|
|
28
|
+
overwrite?: boolean;
|
|
29
|
+
strategy?: "override" | "merge";
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Install multiple files from file mappings
|
|
33
|
+
* Files are always fetched from API endpoint.
|
|
34
|
+
*/
|
|
35
|
+
export declare function installFiles(projectPath: string, fileMappings: FileMapping[], context: ProjectContext, variables: Record<string, string> | undefined, options: {
|
|
36
|
+
overwrite?: boolean;
|
|
37
|
+
dryRun?: boolean;
|
|
38
|
+
componentType: "feature" | "block" | "component" | "template";
|
|
39
|
+
componentName: string;
|
|
40
|
+
variant?: string;
|
|
41
|
+
registryEntry?: {
|
|
42
|
+
requiresSubscription?: boolean;
|
|
43
|
+
subscriptionTier?: number;
|
|
44
|
+
};
|
|
45
|
+
}): Promise<{
|
|
46
|
+
installed: string[];
|
|
47
|
+
skipped: string[];
|
|
48
|
+
conflicts: string[];
|
|
49
|
+
}>;
|
|
50
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/installers/files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,GACjB,MAAM,CAYR;AA8BD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAGT;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACtC,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;CAC5B,GACL,OAAO,CAAC,IAAI,CAAC,CAmCf;AA0BD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAK,EACtC,OAAO,EAAE;IACP,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,GACA,OAAO,CAAC;IACT,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC,CAqGD"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Installer
|
|
3
|
+
*
|
|
4
|
+
* Handles file installation, template substitution, and path resolution.
|
|
5
|
+
* Always uses API endpoint for fetching files.
|
|
6
|
+
*/
|
|
7
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { join, dirname } from "path";
|
|
10
|
+
import { fetchComponentFile, checkSubscription } from "../api/client.js";
|
|
11
|
+
/**
|
|
12
|
+
* Resolve template variables in a path
|
|
13
|
+
*/
|
|
14
|
+
export function resolveTemplatePath(path, context, variables = {}) {
|
|
15
|
+
let resolved = path;
|
|
16
|
+
// Built-in variables
|
|
17
|
+
const srcDir = context.structure.hasSrcFolder ? "src" : "";
|
|
18
|
+
const appDir = context.structure.hasSrcFolder ? "src/app" : "app";
|
|
19
|
+
const allVariables = {
|
|
20
|
+
SRC_DIR: srcDir,
|
|
21
|
+
APP_DIR: appDir,
|
|
22
|
+
...variables,
|
|
23
|
+
};
|
|
24
|
+
// Replace all variables
|
|
25
|
+
for (const [key, value] of Object.entries(allVariables)) {
|
|
26
|
+
const placeholder = `{{${key}}}`;
|
|
27
|
+
resolved = resolved.replace(new RegExp(placeholder, "g"), value);
|
|
28
|
+
}
|
|
29
|
+
// Clean up empty path segments
|
|
30
|
+
resolved = resolved.replace(/\/+/g, "/").replace(/^\//, "");
|
|
31
|
+
return resolved;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Apply template substitution to file content
|
|
35
|
+
*/
|
|
36
|
+
export function applyTemplateSubstitution(content, variables) {
|
|
37
|
+
let result = content;
|
|
38
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
39
|
+
const placeholder = `{{${key}}}`;
|
|
40
|
+
result = result.replace(new RegExp(placeholder, "g"), value);
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Merge JSON content with existing JSON file
|
|
46
|
+
*/
|
|
47
|
+
export function mergeJsonContent(existingContent, newContent) {
|
|
48
|
+
try {
|
|
49
|
+
const existing = JSON.parse(existingContent);
|
|
50
|
+
const newData = JSON.parse(newContent);
|
|
51
|
+
// Deep merge the objects
|
|
52
|
+
const merged = deepMerge(existing, newData);
|
|
53
|
+
return JSON.stringify(merged, null, 2);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw new Error(`Failed to merge JSON: ${error}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deep merge two objects
|
|
61
|
+
*/
|
|
62
|
+
function deepMerge(target, source) {
|
|
63
|
+
if (!isObject(target) || !isObject(source)) {
|
|
64
|
+
return source;
|
|
65
|
+
}
|
|
66
|
+
const result = { ...target };
|
|
67
|
+
for (const key in source) {
|
|
68
|
+
if (isObject(source[key]) && isObject(target[key])) {
|
|
69
|
+
result[key] = deepMerge(target[key], source[key]);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
result[key] = source[key];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if value is an object
|
|
79
|
+
*/
|
|
80
|
+
function isObject(value) {
|
|
81
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if file exists at target location
|
|
85
|
+
*/
|
|
86
|
+
export function checkFileExists(projectPath, targetPath) {
|
|
87
|
+
const fullPath = join(projectPath, targetPath);
|
|
88
|
+
return existsSync(fullPath);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Install a single file
|
|
92
|
+
*/
|
|
93
|
+
export async function installFile(sourceContent, projectPath, targetPath, variables = {}, options = {}) {
|
|
94
|
+
const fullTargetPath = join(projectPath, targetPath);
|
|
95
|
+
const fileExists = existsSync(fullTargetPath);
|
|
96
|
+
// Apply template substitution
|
|
97
|
+
let processedContent = applyTemplateSubstitution(sourceContent, variables);
|
|
98
|
+
// Handle merge strategy for existing files
|
|
99
|
+
if (fileExists && options.strategy === "merge") {
|
|
100
|
+
// Check if it's a JSON file
|
|
101
|
+
if (targetPath.endsWith(".json")) {
|
|
102
|
+
const existingContent = await readFile(fullTargetPath, "utf-8");
|
|
103
|
+
processedContent = mergeJsonContent(existingContent, processedContent);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
throw new Error(`Merge strategy only supported for JSON files: ${targetPath}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (fileExists &&
|
|
110
|
+
!options.overwrite &&
|
|
111
|
+
options.strategy !== "merge" &&
|
|
112
|
+
options.strategy !== "override") {
|
|
113
|
+
// File exists and we're not overwriting, merging, or using override strategy
|
|
114
|
+
throw new Error(`File already exists: ${targetPath}`);
|
|
115
|
+
}
|
|
116
|
+
// If strategy is 'override', we automatically overwrite (no error thrown)
|
|
117
|
+
// Ensure directory exists
|
|
118
|
+
const dir = dirname(fullTargetPath);
|
|
119
|
+
await mkdir(dir, { recursive: true });
|
|
120
|
+
// Write file
|
|
121
|
+
await writeFile(fullTargetPath, processedContent, "utf-8");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Fetch file content from API endpoint
|
|
125
|
+
*/
|
|
126
|
+
async function fetchFileFromAPI(type, name, filePath, variant, requireAuth) {
|
|
127
|
+
try {
|
|
128
|
+
return await fetchComponentFile(type, name, filePath, { variant, requireAuth });
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (error instanceof Error && error.message.includes("Access denied")) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
throw new Error(`Failed to fetch file from API: ${error instanceof Error ? error.message : String(error)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Install multiple files from file mappings
|
|
139
|
+
* Files are always fetched from API endpoint.
|
|
140
|
+
*/
|
|
141
|
+
export async function installFiles(projectPath, fileMappings, context, variables = {}, options) {
|
|
142
|
+
const installed = [];
|
|
143
|
+
const skipped = [];
|
|
144
|
+
const conflicts = [];
|
|
145
|
+
// Determine if authentication is required based on registry entry
|
|
146
|
+
// This prevents repeated authentication prompts for paid components
|
|
147
|
+
const requireAuth = options.registryEntry?.requiresSubscription === true &&
|
|
148
|
+
(options.registryEntry.subscriptionTier || 0) > 0;
|
|
149
|
+
// Check subscription before installing
|
|
150
|
+
// Note: This is a secondary check - the main check should happen in add.ts
|
|
151
|
+
// This is here as a safety net, but we should fail if subscription check fails
|
|
152
|
+
// If registryEntry is provided and component is free, skip the check
|
|
153
|
+
if (options.componentType && options.componentName) {
|
|
154
|
+
try {
|
|
155
|
+
const accessCheck = await checkSubscription(options.componentType, options.componentName, options.registryEntry);
|
|
156
|
+
if (!accessCheck.accessible) {
|
|
157
|
+
throw new Error(accessCheck.reason ||
|
|
158
|
+
"Subscription required. Visit https://tailar.dev/choose-plan to upgrade.");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
// Always throw subscription/authentication errors - don't silently continue
|
|
163
|
+
if (error instanceof Error &&
|
|
164
|
+
(error.message.includes("Subscription") ||
|
|
165
|
+
error.message.includes("Authentication") ||
|
|
166
|
+
error.message.includes("Access denied"))) {
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
// For other errors, also throw to prevent installation without proper verification
|
|
170
|
+
throw new Error(`Failed to verify subscription access: ${error instanceof Error ? error.message : String(error)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (const mapping of fileMappings) {
|
|
174
|
+
// Resolve target path
|
|
175
|
+
const targetPath = resolveTemplatePath(mapping.target, context, variables);
|
|
176
|
+
// Determine strategy (default to override)
|
|
177
|
+
const strategy = mapping.strategy || "override";
|
|
178
|
+
// For merge and override strategies, we don't check conflicts upfront
|
|
179
|
+
// They handle existing files automatically (merge merges, override overwrites)
|
|
180
|
+
// Only check conflicts if no explicit strategy is set and overwrite is not enabled
|
|
181
|
+
if (!mapping.strategy &&
|
|
182
|
+
checkFileExists(projectPath, targetPath) &&
|
|
183
|
+
!options.overwrite) {
|
|
184
|
+
conflicts.push(targetPath);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
// If strategy is explicitly set to 'override', treat it as overwrite=true
|
|
188
|
+
const effectiveOverwrite = options.overwrite || mapping.strategy === "override";
|
|
189
|
+
// Skip if dry run
|
|
190
|
+
if (options.dryRun) {
|
|
191
|
+
installed.push(targetPath);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
let sourceContent;
|
|
196
|
+
// Always fetch from API
|
|
197
|
+
sourceContent = await fetchFileFromAPI(options.componentType, options.componentName, mapping.source, options.variant, requireAuth);
|
|
198
|
+
// Install file
|
|
199
|
+
await installFile(sourceContent, projectPath, targetPath, variables, {
|
|
200
|
+
overwrite: effectiveOverwrite,
|
|
201
|
+
strategy: strategy,
|
|
202
|
+
});
|
|
203
|
+
installed.push(targetPath);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
throw new Error(`Failed to install ${targetPath}: ${error}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { installed, skipped, conflicts };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/installers/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic install of a registry feature (same pipeline as tailar add).
|
|
3
|
+
*/
|
|
4
|
+
export interface InstallFeatureOptions {
|
|
5
|
+
yes?: boolean;
|
|
6
|
+
force?: boolean;
|
|
7
|
+
variant?: string;
|
|
8
|
+
provider?: string;
|
|
9
|
+
/** Skip prompts; merged into answers for variant resolution */
|
|
10
|
+
presetAnswers?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface InstallFeatureResult {
|
|
13
|
+
postInstallSteps: unknown[];
|
|
14
|
+
hasDependencies: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Install a single registry entry by name. Caller must install dependencies first if needed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function installFeature(projectPath: string, name: string, options?: InstallFeatureOptions): Promise<InstallFeatureResult>;
|
|
20
|
+
//# sourceMappingURL=install-feature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-feature.d.ts","sourceRoot":"","sources":["../../src/installers/install-feature.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,OAAO,EAAE,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAYD;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAgK/B"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic install of a registry feature (same pipeline as tailar add).
|
|
3
|
+
*/
|
|
4
|
+
import { readConfig, writeConfig, addInstalledItem, } from '../utils/config.js';
|
|
5
|
+
import { detectPackageManager } from '../utils/package-manager.js';
|
|
6
|
+
import { detectProjectStructure } from '../utils/validation.js';
|
|
7
|
+
import { loadRegistry } from '../registry/loader.js';
|
|
8
|
+
import { getEntry, getVariant } from '../registry/query.js';
|
|
9
|
+
import { runPrompts } from '../utils/prompts.js';
|
|
10
|
+
import { installFiles } from './files.js';
|
|
11
|
+
import { mergeDependencies, collectDependencies } from './dependencies.js';
|
|
12
|
+
import { collectTemplateVariables, extractVariablesFromAnswers, mergeVariables, } from './templates.js';
|
|
13
|
+
import { isAuthenticated, authenticate } from '../auth/flow.js';
|
|
14
|
+
import { checkSubscription } from '../api/client.js';
|
|
15
|
+
import { logger } from '../utils/logger.js';
|
|
16
|
+
function defaultAnswersFromQuestions(questions) {
|
|
17
|
+
const out = {};
|
|
18
|
+
for (const q of questions) {
|
|
19
|
+
if (q.default !== undefined)
|
|
20
|
+
out[q.name] = q.default;
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Install a single registry entry by name. Caller must install dependencies first if needed.
|
|
26
|
+
*/
|
|
27
|
+
export async function installFeature(projectPath, name, options = {}) {
|
|
28
|
+
const config = await readConfig(projectPath);
|
|
29
|
+
if (!config) {
|
|
30
|
+
throw new Error('Tailar not initialized. Run tailar init first.');
|
|
31
|
+
}
|
|
32
|
+
const structure = detectProjectStructure(projectPath);
|
|
33
|
+
const packageManager = detectPackageManager(projectPath);
|
|
34
|
+
const context = {
|
|
35
|
+
root: projectPath,
|
|
36
|
+
packageManager,
|
|
37
|
+
structure,
|
|
38
|
+
config,
|
|
39
|
+
};
|
|
40
|
+
const registry = await loadRegistry();
|
|
41
|
+
const entry = getEntry(registry, name);
|
|
42
|
+
if (!entry) {
|
|
43
|
+
throw new Error(`Entry not found: ${name}`);
|
|
44
|
+
}
|
|
45
|
+
const requiresSubscription = entry.requiresSubscription === true && (entry.subscriptionTier || 0) > 0;
|
|
46
|
+
if (requiresSubscription) {
|
|
47
|
+
if (!(await isAuthenticated())) {
|
|
48
|
+
await authenticate();
|
|
49
|
+
}
|
|
50
|
+
const accessCheck = await checkSubscription(entry.type, name);
|
|
51
|
+
if (!accessCheck.accessible) {
|
|
52
|
+
throw new Error(accessCheck.reason || 'Subscription required');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
let answers = {};
|
|
56
|
+
if (entry.questions && entry.questions.length > 0) {
|
|
57
|
+
if (options.presetAnswers) {
|
|
58
|
+
answers = { ...options.presetAnswers };
|
|
59
|
+
}
|
|
60
|
+
else if (!options.yes) {
|
|
61
|
+
answers = await runPrompts(entry.questions, {
|
|
62
|
+
skipPrompts: false,
|
|
63
|
+
defaults: {
|
|
64
|
+
variant: options.variant,
|
|
65
|
+
provider: options.provider,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
answers = defaultAnswersFromQuestions(entry.questions);
|
|
71
|
+
if (options.variant)
|
|
72
|
+
answers.variant = options.variant;
|
|
73
|
+
if (options.provider) {
|
|
74
|
+
const resolver = entry.variantResolver;
|
|
75
|
+
if (resolver?.answerKey) {
|
|
76
|
+
answers[resolver.answerKey] = options.provider;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (options.provider && entry.variantResolver?.answerKey) {
|
|
82
|
+
answers[entry.variantResolver.answerKey] = options.provider;
|
|
83
|
+
}
|
|
84
|
+
if (options.variant)
|
|
85
|
+
answers.variant = options.variant;
|
|
86
|
+
let selectedVariant;
|
|
87
|
+
if (options.variant) {
|
|
88
|
+
selectedVariant = options.variant;
|
|
89
|
+
}
|
|
90
|
+
else if (typeof answers.variant === 'string') {
|
|
91
|
+
selectedVariant = answers.variant;
|
|
92
|
+
}
|
|
93
|
+
else if (entry.variantResolver) {
|
|
94
|
+
const resolver = entry.variantResolver;
|
|
95
|
+
if (resolver.detect && context.config) {
|
|
96
|
+
const installedFeature = context.config.installed.features.find((f) => f.name === resolver.detect);
|
|
97
|
+
if (installedFeature?.variant) {
|
|
98
|
+
if (resolver.mapping) {
|
|
99
|
+
const mapped = resolver.mapping[installedFeature.variant];
|
|
100
|
+
selectedVariant = mapped || installedFeature.variant;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
selectedVariant = installedFeature.variant;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (!selectedVariant && resolver.answerKey) {
|
|
108
|
+
const answerValue = options.provider ?? answers[resolver.answerKey];
|
|
109
|
+
if (answerValue !== undefined) {
|
|
110
|
+
if (resolver.mapping) {
|
|
111
|
+
const mapped = resolver.mapping[String(answerValue)];
|
|
112
|
+
selectedVariant = mapped || String(answerValue);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
selectedVariant = String(answerValue);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!selectedVariant && resolver.default) {
|
|
120
|
+
selectedVariant = resolver.default;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const variant = selectedVariant ? getVariant(entry, selectedVariant) : undefined;
|
|
124
|
+
let templateVars = {};
|
|
125
|
+
if (entry.templates && entry.templates.length > 0) {
|
|
126
|
+
templateVars = await collectTemplateVariables(entry.templates, {
|
|
127
|
+
skipPrompts: true,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const answerVars = extractVariablesFromAnswers(answers);
|
|
131
|
+
const allVars = mergeVariables(templateVars, answerVars);
|
|
132
|
+
let files = [...entry.files];
|
|
133
|
+
if (variant?.files)
|
|
134
|
+
files.push(...variant.files);
|
|
135
|
+
const result = await installFiles(context.root, files, context, allVars, {
|
|
136
|
+
overwrite: options.force || true,
|
|
137
|
+
componentType: entry.type,
|
|
138
|
+
componentName: entry.name,
|
|
139
|
+
variant: selectedVariant,
|
|
140
|
+
registryEntry: entry,
|
|
141
|
+
});
|
|
142
|
+
if (result.conflicts.length > 0 && !options.force) {
|
|
143
|
+
throw new Error(`File conflicts: ${result.conflicts.join(', ')}`);
|
|
144
|
+
}
|
|
145
|
+
logger.success(`Installed ${result.installed.length} files for ${entry.label}`);
|
|
146
|
+
const deps = collectDependencies(entry, selectedVariant);
|
|
147
|
+
let hasDependencies = false;
|
|
148
|
+
if (deps.length > 0) {
|
|
149
|
+
await mergeDependencies(context.root, deps);
|
|
150
|
+
hasDependencies = true;
|
|
151
|
+
}
|
|
152
|
+
const postInstallSteps = [
|
|
153
|
+
...(entry.postInstall || []),
|
|
154
|
+
...(variant?.postInstall || []),
|
|
155
|
+
];
|
|
156
|
+
const provider = options.provider ||
|
|
157
|
+
answers.emailProvider ||
|
|
158
|
+
answers.dbProvider;
|
|
159
|
+
if (!context.config)
|
|
160
|
+
throw new Error('Config missing');
|
|
161
|
+
const updatedConfig = addInstalledItem(context.config, entry.type, name, {
|
|
162
|
+
variant: selectedVariant,
|
|
163
|
+
provider,
|
|
164
|
+
});
|
|
165
|
+
await writeConfig(context.root, updatedConfig);
|
|
166
|
+
context.config = updatedConfig;
|
|
167
|
+
return { postInstallSteps, hasDependencies };
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=install-feature.js.map
|