create-next-hydra 0.2.0 → 0.3.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/README.md +34 -3
- package/dist/composition/add.d.ts.map +1 -1
- package/dist/composition/add.js +64 -33
- package/dist/composition/catalog.d.ts +4 -1
- package/dist/composition/catalog.d.ts.map +1 -1
- package/dist/composition/catalog.js +22 -6
- package/dist/composition/format.d.ts.map +1 -1
- package/dist/composition/format.js +3 -1
- package/dist/composition/packages.d.ts +2 -2
- package/dist/composition/packages.d.ts.map +1 -1
- package/dist/composition/packages.js +13 -12
- package/dist/composition/planner.d.ts.map +1 -1
- package/dist/composition/planner.js +88 -42
- package/dist/composition/schema.d.ts +59 -0
- package/dist/composition/schema.d.ts.map +1 -1
- package/dist/composition/schema.js +52 -1
- package/dist/composition/types.d.ts +26 -2
- package/dist/composition/types.d.ts.map +1 -1
- package/dist/composition/typescript-paths.d.ts +6 -0
- package/dist/composition/typescript-paths.d.ts.map +1 -0
- package/dist/composition/typescript-paths.js +157 -0
- package/dist/composition/use.d.ts.map +1 -1
- package/dist/composition/use.js +5 -0
- package/dist/composition/workspace.d.ts.map +1 -1
- package/dist/composition/workspace.js +5 -3
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +8 -1
- package/dist/sanitize.d.ts.map +1 -1
- package/dist/sanitize.js +89 -2
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +5 -0
- package/package.json +11 -4
- package/schema/selection-definition.json +65 -3
package/dist/sanitize.js
CHANGED
|
@@ -1,6 +1,90 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile, readdir, writeFile } from "node:fs/promises";
|
|
1
3
|
import path from "node:path";
|
|
2
4
|
import { SANITIZE_REMOVE_PATHS, SANITIZE_REMOVE_ROOT_DEPENDENCIES, SANITIZE_REMOVE_ROOT_DEV_DEPENDENCIES, SANITIZE_REMOVE_SCRIPTS, } from "./constants.js";
|
|
3
|
-
import { normalizePackageName, readJsonFile, removePath, writeJsonFile, } from "./fs-utils.js";
|
|
5
|
+
import { normalizePackageName, pathExists, readJsonFile, removePath, writeJsonFile, } from "./fs-utils.js";
|
|
6
|
+
const MAINTAINER_PORTLESS_PROJECT = "next-hydra";
|
|
7
|
+
const MAX_DNS_LABEL_LENGTH = 63;
|
|
8
|
+
const PORTLESS_PROJECT_HASH_LENGTH = 6;
|
|
9
|
+
const PORTLESS_PROJECT_FILES = [
|
|
10
|
+
".vscode/launch.json",
|
|
11
|
+
"apps/admin/.env.example",
|
|
12
|
+
"apps/api/.env.example",
|
|
13
|
+
"apps/drupal/recipes/next-hydra-starter/README.md",
|
|
14
|
+
"apps/drupal/recipes/next-hydra-starter/config/core.entity_view_display.node.article.default.yml",
|
|
15
|
+
"apps/drupal/recipes/next-hydra-starter/config/core.entity_view_display.node.landing_page.default.yml",
|
|
16
|
+
"apps/drupal/recipes/next-hydra-starter/config/next.next_site.next_hydra.yml",
|
|
17
|
+
"apps/storybook/README.md",
|
|
18
|
+
"apps/web/.env.example",
|
|
19
|
+
"packages/cms-contentstack/README.md",
|
|
20
|
+
"packages/cms-contentstack/cli/index.ts",
|
|
21
|
+
"packages/cms-contentstack/cli/provisioning/provision.test.ts",
|
|
22
|
+
"packages/cms-contentstack/cli/provisioning/recipe-live.test.ts",
|
|
23
|
+
];
|
|
24
|
+
const portlessApplicationName = (applicationName, projectName) => {
|
|
25
|
+
const [service] = applicationName.split(".");
|
|
26
|
+
return `${service}.${projectName}`;
|
|
27
|
+
};
|
|
28
|
+
const portlessProjectName = (packageName) => {
|
|
29
|
+
const sanitized = packageName
|
|
30
|
+
.toLowerCase()
|
|
31
|
+
.replaceAll(/[^a-z0-9-]/gu, "-")
|
|
32
|
+
.replaceAll(/-{2,}/gu, "-")
|
|
33
|
+
.replaceAll(/^-+|-+$/gu, "");
|
|
34
|
+
if (sanitized.length <= MAX_DNS_LABEL_LENGTH) {
|
|
35
|
+
return sanitized;
|
|
36
|
+
}
|
|
37
|
+
const hash = createHash("sha256")
|
|
38
|
+
.update(sanitized)
|
|
39
|
+
.digest("hex")
|
|
40
|
+
.slice(0, PORTLESS_PROJECT_HASH_LENGTH);
|
|
41
|
+
const prefix = sanitized
|
|
42
|
+
.slice(0, MAX_DNS_LABEL_LENGTH - PORTLESS_PROJECT_HASH_LENGTH - 1)
|
|
43
|
+
.replaceAll(/-+$/gu, "");
|
|
44
|
+
return `${prefix}-${hash}`;
|
|
45
|
+
};
|
|
46
|
+
const rewritePackagePortlessProject = async (packageJsonPath, projectName) => {
|
|
47
|
+
if (!(await pathExists(packageJsonPath))) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const packageJson = await readJsonFile(packageJsonPath);
|
|
51
|
+
const config = packageJson.portless;
|
|
52
|
+
if (!config?.name) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
config.name = portlessApplicationName(config.name, projectName);
|
|
56
|
+
await writeJsonFile(packageJsonPath, packageJson);
|
|
57
|
+
};
|
|
58
|
+
const rewriteApplicationPortlessConfigs = async (targetPath, projectName) => {
|
|
59
|
+
const applicationsPath = path.join(targetPath, "apps");
|
|
60
|
+
if (!(await pathExists(applicationsPath))) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const applicationEntries = await readdir(applicationsPath, {
|
|
64
|
+
withFileTypes: true,
|
|
65
|
+
});
|
|
66
|
+
const applicationDirectories = applicationEntries.filter((entry) => entry.isDirectory());
|
|
67
|
+
await Promise.all(applicationDirectories.map(async ({ name }) => {
|
|
68
|
+
await rewritePackagePortlessProject(path.join(applicationsPath, name, "package.json"), projectName);
|
|
69
|
+
}));
|
|
70
|
+
};
|
|
71
|
+
const rewritePortlessProject = async (targetPath, packageName) => {
|
|
72
|
+
const projectName = portlessProjectName(packageName);
|
|
73
|
+
await rewriteApplicationPortlessConfigs(targetPath, projectName);
|
|
74
|
+
const maintainerHostname = `.${MAINTAINER_PORTLESS_PROJECT}.localhost`;
|
|
75
|
+
const projectHostname = `.${projectName}.localhost`;
|
|
76
|
+
await Promise.all(PORTLESS_PROJECT_FILES.map(async (relativePath) => {
|
|
77
|
+
const filePath = path.join(targetPath, relativePath);
|
|
78
|
+
if (!(await pathExists(filePath))) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const source = await readFile(filePath, "utf-8");
|
|
82
|
+
const rewritten = source.replaceAll(maintainerHostname, projectHostname);
|
|
83
|
+
if (rewritten !== source) {
|
|
84
|
+
await writeFile(filePath, rewritten, "utf-8");
|
|
85
|
+
}
|
|
86
|
+
}));
|
|
87
|
+
};
|
|
4
88
|
export async function sanitizeStarter({ targetPath, targetName, registryAuthoringPaths = [], }) {
|
|
5
89
|
await Promise.all([...SANITIZE_REMOVE_PATHS, ...registryAuthoringPaths].map(async (relativePath) => {
|
|
6
90
|
await removePath(path.join(targetPath, relativePath));
|
|
@@ -18,6 +102,9 @@ export async function sanitizeStarter({ targetPath, targetName, registryAuthorin
|
|
|
18
102
|
for (const dependency of SANITIZE_REMOVE_ROOT_DEV_DEPENDENCIES) {
|
|
19
103
|
delete packageJson.devDependencies?.[dependency];
|
|
20
104
|
}
|
|
21
|
-
await
|
|
105
|
+
await Promise.all([
|
|
106
|
+
writeJsonFile(packageJsonPath, packageJson),
|
|
107
|
+
rewritePortlessProject(targetPath, packageName),
|
|
108
|
+
]);
|
|
22
109
|
return { packageName };
|
|
23
110
|
}
|
package/dist/scaffold.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EACV,aAAa,EAEb,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,KAAK,oBAAoB,GAAG;IAC1B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AA8KF,wBAAsB,eAAe,CACnC,OAAO,EAAE,aAAa,EACtB,YAAY,GAAE,oBAAyB,GACtC,OAAO,CAAC,cAAc,CAAC,CA2OzB"}
|
package/dist/scaffold.js
CHANGED
|
@@ -7,6 +7,7 @@ import { addCatalogReferences, loadGitHubSourceRegistryCatalog, loadSourceRegist
|
|
|
7
7
|
import { formatCompositionPlan } from "./composition/format.js";
|
|
8
8
|
import { installPreparedComposition, prepareComposition, validatePackageRequirementTargets, } from "./composition/install.js";
|
|
9
9
|
import { planComposition, selectionFromPreset } from "./composition/planner.js";
|
|
10
|
+
import { applyTypeScriptPathAliases } from "./composition/typescript-paths.js";
|
|
10
11
|
import { applyPackageRequirements, applyPnpmPatches, removeWorkspaceTargets, } from "./composition/workspace.js";
|
|
11
12
|
import { DEFAULT_PACKAGE_MANAGER } from "./constants.js";
|
|
12
13
|
import { ensureParentDirectory, isDirectoryEmpty, pathExists, toDisplayPath, } from "./fs-utils.js";
|
|
@@ -186,6 +187,7 @@ export async function scaffoldProject(options, dependencies = {}) {
|
|
|
186
187
|
"remove variable provider source",
|
|
187
188
|
"install selected source",
|
|
188
189
|
"update package aliases",
|
|
190
|
+
"update TypeScript paths",
|
|
189
191
|
"update pnpm patches",
|
|
190
192
|
"remove maintainer-only files",
|
|
191
193
|
"install dependencies",
|
|
@@ -237,6 +239,9 @@ export async function scaffoldProject(options, dependencies = {}) {
|
|
|
237
239
|
await runStep("update package aliases", async () => {
|
|
238
240
|
await applyPackageRequirements(targetPath, plan);
|
|
239
241
|
});
|
|
242
|
+
await runStep("update TypeScript paths", async () => {
|
|
243
|
+
await applyTypeScriptPathAliases(targetPath, plan);
|
|
244
|
+
});
|
|
240
245
|
await runStep("update pnpm patches", async () => {
|
|
241
246
|
await applyPnpmPatches(targetPath, plan);
|
|
242
247
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-next-hydra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI to scaffold a new next-hydra project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -39,15 +39,22 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@clack/prompts": "^0.11.0",
|
|
41
41
|
"commander": "^14.0.0",
|
|
42
|
+
"jsonc-parser": "^3.3.1",
|
|
42
43
|
"shadcn": "^4.16.2",
|
|
43
44
|
"yaml": "^2.9.0",
|
|
44
45
|
"zod": "^3.25.28"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@types/node": "24.13.3",
|
|
49
|
+
"effect": "4.0.0-rc.111",
|
|
48
50
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
49
51
|
"vitest": "4.1.11",
|
|
50
|
-
"@repo/
|
|
52
|
+
"@repo/actions": "0.0.0",
|
|
53
|
+
"@repo/auth-workos": "0.0.0",
|
|
54
|
+
"@repo/auth-clerk": "0.0.0",
|
|
55
|
+
"@repo/commerce": "0.0.0",
|
|
56
|
+
"@repo/typescript-config": "0.0.0",
|
|
57
|
+
"@repo/registration": "0.0.0"
|
|
51
58
|
},
|
|
52
59
|
"engines": {
|
|
53
60
|
"node": "24.x"
|
|
@@ -61,8 +68,8 @@
|
|
|
61
68
|
"pack": "npm pack",
|
|
62
69
|
"publish:dry-run": "npm publish --access public --dry-run",
|
|
63
70
|
"publish:public": "npm publish --access public",
|
|
64
|
-
"test": "vitest run --exclude 'tests/e2e/**'",
|
|
65
|
-
"test:e2e": "vitest run tests/e2e",
|
|
71
|
+
"test": "NODE_ENV=test vitest run --exclude 'tests/e2e/**'",
|
|
72
|
+
"test:e2e": "NODE_ENV=test vitest run tests/e2e",
|
|
66
73
|
"typecheck": "pnpm --workspace-root exec tsc --noEmit --project packages/create-next-hydra/tsconfig.json"
|
|
67
74
|
}
|
|
68
75
|
}
|
|
@@ -60,6 +60,20 @@
|
|
|
60
60
|
"slot": {
|
|
61
61
|
"enum": ["auth", "cms", "commerce"]
|
|
62
62
|
},
|
|
63
|
+
"binding": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": ["specifier"],
|
|
67
|
+
"properties": {
|
|
68
|
+
"specifier": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"minLength": 1
|
|
71
|
+
},
|
|
72
|
+
"sourcePath": {
|
|
73
|
+
"$ref": "#/$defs/workspaceFilePath"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
63
77
|
"compatibility": {
|
|
64
78
|
"type": "object",
|
|
65
79
|
"additionalProperties": false,
|
|
@@ -101,7 +115,14 @@
|
|
|
101
115
|
},
|
|
102
116
|
"name": {
|
|
103
117
|
"type": "string",
|
|
104
|
-
"minLength": 1
|
|
118
|
+
"minLength": 1,
|
|
119
|
+
"not": {
|
|
120
|
+
"enum": [
|
|
121
|
+
"@repo/auth",
|
|
122
|
+
"@repo/cms",
|
|
123
|
+
"@repo/commerce-provider"
|
|
124
|
+
]
|
|
125
|
+
}
|
|
105
126
|
},
|
|
106
127
|
"specifier": {
|
|
107
128
|
"type": "string",
|
|
@@ -110,6 +131,29 @@
|
|
|
110
131
|
}
|
|
111
132
|
}
|
|
112
133
|
},
|
|
134
|
+
"providerDependencies": {
|
|
135
|
+
"type": "array",
|
|
136
|
+
"items": {
|
|
137
|
+
"type": "object",
|
|
138
|
+
"additionalProperties": false,
|
|
139
|
+
"required": ["cwd", "section", "slot"],
|
|
140
|
+
"properties": {
|
|
141
|
+
"cwd": {
|
|
142
|
+
"$ref": "#/$defs/workspacePath"
|
|
143
|
+
},
|
|
144
|
+
"section": {
|
|
145
|
+
"enum": [
|
|
146
|
+
"dependencies",
|
|
147
|
+
"devDependencies",
|
|
148
|
+
"optionalDependencies"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"slot": {
|
|
152
|
+
"enum": ["auth", "cms", "commerce"]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
113
157
|
"pnpmPatches": {
|
|
114
158
|
"type": "array",
|
|
115
159
|
"items": {
|
|
@@ -187,7 +231,7 @@
|
|
|
187
231
|
"required": ["kind"]
|
|
188
232
|
},
|
|
189
233
|
"then": {
|
|
190
|
-
"required": ["slot"],
|
|
234
|
+
"required": ["binding", "slot"],
|
|
191
235
|
"not": {
|
|
192
236
|
"required": ["selections"]
|
|
193
237
|
}
|
|
@@ -208,6 +252,9 @@
|
|
|
208
252
|
{
|
|
209
253
|
"required": ["slot"]
|
|
210
254
|
},
|
|
255
|
+
{
|
|
256
|
+
"required": ["binding"]
|
|
257
|
+
},
|
|
211
258
|
{
|
|
212
259
|
"required": ["selections"]
|
|
213
260
|
}
|
|
@@ -227,7 +274,22 @@
|
|
|
227
274
|
"then": {
|
|
228
275
|
"required": ["selections"],
|
|
229
276
|
"not": {
|
|
230
|
-
"
|
|
277
|
+
"anyOf": [
|
|
278
|
+
{
|
|
279
|
+
"required": ["slot"]
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"required": ["binding"]
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"properties": {
|
|
286
|
+
"providerDependencies": {
|
|
287
|
+
"minItems": 1
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
"required": ["providerDependencies"]
|
|
291
|
+
}
|
|
292
|
+
]
|
|
231
293
|
}
|
|
232
294
|
}
|
|
233
295
|
}
|