@dunx/create-app 3.2.0 → 3.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/dist/agents.d.ts +0 -1
- package/dist/{chunk-rv2w0t23.js → chunk-szd4jhfn.js} +28 -28
- package/dist/cli.js +32 -32
- package/dist/index.js +17 -17
- package/package.json +3 -3
- package/templates/minimal/package.json +2 -2
package/dist/agents.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Feature } from './features.js';
|
|
2
|
-
export declare const CLAUDE_POINTER = "# CLAUDE.md\n\nThe instructions for this application live in `AGENTS.md`, imported below so every\nagent reads one file.\n\n@AGENTS.md\n";
|
|
3
2
|
export declare const agents: (name: string, features: readonly Feature[]) => string;
|
|
4
3
|
/** Both files, written for a fixed template and a composed app alike. */
|
|
5
4
|
export declare const agentFiles: (name: string, features: readonly Feature[]) => Readonly<Record<string, string>>;
|
|
@@ -132,7 +132,7 @@ var CONFIG_GROUPS = Object.freeze({
|
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
var BASE_CONFIG = ["appName", "port", "log"];
|
|
135
|
-
var
|
|
135
|
+
var FEATURES2 = [
|
|
136
136
|
{
|
|
137
137
|
name: "notes",
|
|
138
138
|
source: "notes",
|
|
@@ -303,8 +303,8 @@ var FEATURES = [
|
|
|
303
303
|
config: ["appName", "upstream"]
|
|
304
304
|
}
|
|
305
305
|
];
|
|
306
|
-
var
|
|
307
|
-
var byName = new Map(
|
|
306
|
+
var featureNames2 = FEATURES2.map((feature) => feature.name);
|
|
307
|
+
var byName = new Map(FEATURES2.map((feature) => [feature.name, feature]));
|
|
308
308
|
|
|
309
309
|
class UnknownFeatureError extends Error {
|
|
310
310
|
name = "UnknownFeatureError";
|
|
@@ -312,11 +312,11 @@ class UnknownFeatureError extends Error {
|
|
|
312
312
|
var resolveFeatures = (requested) => {
|
|
313
313
|
const unknown = requested.filter((name) => !byName.has(name));
|
|
314
314
|
if (unknown.length > 0) {
|
|
315
|
-
throw new UnknownFeatureError(`Unknown feature${unknown.length === 1 ? "" : "s"}: ${unknown.join(", ")}. ` + `Available: ${
|
|
315
|
+
throw new UnknownFeatureError(`Unknown feature${unknown.length === 1 ? "" : "s"}: ${unknown.join(", ")}. ` + `Available: ${featureNames2.join(", ")}.`);
|
|
316
316
|
}
|
|
317
317
|
const ordered = [];
|
|
318
318
|
const seen = new Set;
|
|
319
|
-
const rank = new Map(
|
|
319
|
+
const rank = new Map(FEATURES2.map((feature, at) => [feature.name, at]));
|
|
320
320
|
const visit = (name) => {
|
|
321
321
|
if (seen.has(name))
|
|
322
322
|
return;
|
|
@@ -329,7 +329,7 @@ var resolveFeatures = (requested) => {
|
|
|
329
329
|
}
|
|
330
330
|
ordered.push(feature);
|
|
331
331
|
};
|
|
332
|
-
for (const feature of
|
|
332
|
+
for (const feature of FEATURES2) {
|
|
333
333
|
if (requested.includes(feature.name))
|
|
334
334
|
visit(feature.name);
|
|
335
335
|
}
|
|
@@ -496,10 +496,10 @@ var manifest = (features) => {
|
|
|
496
496
|
dependencies,
|
|
497
497
|
devDependencies: {
|
|
498
498
|
"@dunx/testing": "__DUNX_VERSION__",
|
|
499
|
-
"@types/bun": ">=1.4.
|
|
499
|
+
"@types/bun": ">=1.4.1",
|
|
500
500
|
typescript: "^5.7.0"
|
|
501
501
|
},
|
|
502
|
-
engines: { bun: ">=1.4.
|
|
502
|
+
engines: { bun: ">=1.4.1" }
|
|
503
503
|
}, null, 2)}
|
|
504
504
|
`;
|
|
505
505
|
};
|
|
@@ -796,8 +796,8 @@ built with no arguments and boot fails saying so.
|
|
|
796
796
|
};
|
|
797
797
|
|
|
798
798
|
// src/scaffold.ts
|
|
799
|
-
var
|
|
800
|
-
var
|
|
799
|
+
var TEMPLATES2 = Object.freeze(["minimal"]);
|
|
800
|
+
var VERSION_PLACEHOLDER2 = "__DUNX_VERSION__";
|
|
801
801
|
var RENAMED = Object.freeze({
|
|
802
802
|
_gitignore: ".gitignore",
|
|
803
803
|
"_bunfig.toml": "bunfig.toml"
|
|
@@ -808,19 +808,19 @@ var IGNORED_WHEN_EMPTY = new Set([
|
|
|
808
808
|
".gitkeep",
|
|
809
809
|
"LICENSE"
|
|
810
810
|
]);
|
|
811
|
-
var
|
|
811
|
+
var blockingEntries2 = (directory) => existsSync(directory) ? readdirSync(directory).filter((entry) => !IGNORED_WHEN_EMPTY.has(entry)).sort() : [];
|
|
812
812
|
|
|
813
|
-
class
|
|
813
|
+
class ScaffoldError2 extends Error {
|
|
814
814
|
name = "ScaffoldError";
|
|
815
815
|
}
|
|
816
816
|
var templatesRoot = () => resolve(dirname(fileURLToPath(import.meta.url)), "..", "templates");
|
|
817
|
-
var
|
|
817
|
+
var isValidPackageName2 = (name) => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);
|
|
818
818
|
var packageVersion = async () => {
|
|
819
819
|
const file = Bun.file(join(templatesRoot(), "..", "package.json"));
|
|
820
820
|
const json = await file.json();
|
|
821
821
|
return json.version ?? "0.0.0";
|
|
822
822
|
};
|
|
823
|
-
var fill = (contents, name, version) => contents.replaceAll(
|
|
823
|
+
var fill = (contents, name, version) => contents.replaceAll(VERSION_PLACEHOLDER2, version).replaceAll("__DUNX_APP_NAME__", name);
|
|
824
824
|
var generated = (name, features) => {
|
|
825
825
|
const groups = configGroupsFor(features);
|
|
826
826
|
return {
|
|
@@ -832,30 +832,30 @@ var generated = (name, features) => {
|
|
|
832
832
|
"src/config.ts": config(name, groups)
|
|
833
833
|
};
|
|
834
834
|
};
|
|
835
|
-
var
|
|
835
|
+
var scaffold2 = async (options) => {
|
|
836
836
|
const template = options.template ?? "minimal";
|
|
837
|
-
if (!
|
|
838
|
-
throw new
|
|
837
|
+
if (!TEMPLATES2.includes(template)) {
|
|
838
|
+
throw new ScaffoldError2(`Unknown template "${template}". Available: ${TEMPLATES2.join(", ")}.`);
|
|
839
839
|
}
|
|
840
840
|
const requested = options.features ?? [];
|
|
841
841
|
let features = [];
|
|
842
842
|
try {
|
|
843
843
|
features = resolveFeatures(requested);
|
|
844
844
|
} catch (error) {
|
|
845
|
-
throw new
|
|
845
|
+
throw new ScaffoldError2(error instanceof Error ? error.message : String(error));
|
|
846
846
|
}
|
|
847
847
|
const composing = features.length > 0;
|
|
848
848
|
const directory = resolve(options.cwd ?? process.cwd(), options.target);
|
|
849
849
|
const name = options.name ?? basename(directory);
|
|
850
|
-
if (!
|
|
851
|
-
throw new
|
|
850
|
+
if (!isValidPackageName2(name)) {
|
|
851
|
+
throw new ScaffoldError2(`"${name}" is not a usable package name. Pass --name to choose one.`);
|
|
852
852
|
}
|
|
853
853
|
if (options.force !== true) {
|
|
854
|
-
const blocking =
|
|
854
|
+
const blocking = blockingEntries2(directory);
|
|
855
855
|
if (blocking.length > 0) {
|
|
856
856
|
const shown = blocking.slice(0, 3).join(", ");
|
|
857
857
|
const rest = blocking.length > 3 ? `, +${blocking.length - 3} more` : "";
|
|
858
|
-
throw new
|
|
858
|
+
throw new ScaffoldError2(`${directory} is not empty (${shown}${rest}). ` + `Pass --force to write into it anyway.`);
|
|
859
859
|
}
|
|
860
860
|
}
|
|
861
861
|
const version = options.version ?? `^${await packageVersion()}`;
|
|
@@ -866,8 +866,8 @@ var scaffold = async (options) => {
|
|
|
866
866
|
dot: true,
|
|
867
867
|
onlyFiles: true
|
|
868
868
|
})) {
|
|
869
|
-
const
|
|
870
|
-
const renamed = RENAMED[
|
|
869
|
+
const base = relative.split("/").at(-1) ?? relative;
|
|
870
|
+
const renamed = RENAMED[base];
|
|
871
871
|
const target = join(into, renamed === undefined ? relative : join(dirname(relative), renamed));
|
|
872
872
|
const contents = await Bun.file(join(from, relative)).text();
|
|
873
873
|
await Bun.write(join(directory, target), fill(contents, name, version));
|
|
@@ -883,7 +883,7 @@ var scaffold = async (options) => {
|
|
|
883
883
|
if (!composing) {
|
|
884
884
|
const source = join(templatesRoot(), template);
|
|
885
885
|
if (!existsSync(source)) {
|
|
886
|
-
throw new
|
|
886
|
+
throw new ScaffoldError2(`Template "${template}" is missing from ${source}.`);
|
|
887
887
|
}
|
|
888
888
|
await copyTree(source, ".");
|
|
889
889
|
await writeAll(agentFiles(name, []));
|
|
@@ -897,13 +897,13 @@ var scaffold = async (options) => {
|
|
|
897
897
|
}
|
|
898
898
|
const base = join(templatesRoot(), "base");
|
|
899
899
|
if (!existsSync(base)) {
|
|
900
|
-
throw new
|
|
900
|
+
throw new ScaffoldError2(`The base template is missing from ${base}. Run \`bun run sync:templates\`.`);
|
|
901
901
|
}
|
|
902
902
|
await copyTree(base, ".");
|
|
903
903
|
for (const feature of features) {
|
|
904
904
|
const from = join(templatesRoot(), "features", feature.source);
|
|
905
905
|
if (!existsSync(from)) {
|
|
906
|
-
throw new
|
|
906
|
+
throw new ScaffoldError2(`Feature "${feature.name}" is missing from ${from}. ` + "Run `bun run sync:templates`.");
|
|
907
907
|
}
|
|
908
908
|
await copyTree(from, join("src", feature.source));
|
|
909
909
|
}
|
|
@@ -920,4 +920,4 @@ var scaffold = async (options) => {
|
|
|
920
920
|
};
|
|
921
921
|
};
|
|
922
922
|
|
|
923
|
-
export {
|
|
923
|
+
export { FEATURES2, featureNames2, resolveFeatures, impliedBy, TEMPLATES2, VERSION_PLACEHOLDER2, blockingEntries2, ScaffoldError2, isValidPackageName2, packageVersion, scaffold2 };
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
blockingEntries,
|
|
4
|
+
FEATURES2,
|
|
5
|
+
resolveFeatures,
|
|
7
6
|
impliedBy,
|
|
8
|
-
|
|
7
|
+
blockingEntries2,
|
|
8
|
+
ScaffoldError2,
|
|
9
|
+
isValidPackageName2,
|
|
9
10
|
packageVersion,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from "./chunk-rv2w0t23.js";
|
|
11
|
+
scaffold2
|
|
12
|
+
} from "./chunk-szd4jhfn.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
15
|
import { parseArgs } from "util";
|
|
@@ -169,15 +169,15 @@ class Prompt {
|
|
|
169
169
|
#done = false;
|
|
170
170
|
#cancelled = false;
|
|
171
171
|
#answer;
|
|
172
|
-
press(
|
|
172
|
+
press(key) {
|
|
173
173
|
if (this.#done)
|
|
174
174
|
return;
|
|
175
|
-
if (
|
|
175
|
+
if (key.name === KeyName.Interrupt || key.name === KeyName.Escape) {
|
|
176
176
|
this.#cancelled = true;
|
|
177
177
|
this.#done = true;
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
|
-
this.handle(
|
|
180
|
+
this.handle(key);
|
|
181
181
|
}
|
|
182
182
|
finish(answer) {
|
|
183
183
|
this.#answer = answer;
|
|
@@ -222,8 +222,8 @@ class PromptRunner {
|
|
|
222
222
|
try {
|
|
223
223
|
await new Promise((resolve) => {
|
|
224
224
|
paint();
|
|
225
|
-
this.#tty.open((
|
|
226
|
-
prompt.press(
|
|
225
|
+
this.#tty.open((key) => {
|
|
226
|
+
prompt.press(key);
|
|
227
227
|
if (prompt.done)
|
|
228
228
|
resolve();
|
|
229
229
|
else
|
|
@@ -319,8 +319,8 @@ class ProcessTty extends Tty {
|
|
|
319
319
|
}
|
|
320
320
|
open(onKey) {
|
|
321
321
|
const listener = (chunk) => {
|
|
322
|
-
for (const
|
|
323
|
-
onKey(
|
|
322
|
+
for (const key of this.#decoder.push(chunk))
|
|
323
|
+
onKey(key);
|
|
324
324
|
};
|
|
325
325
|
this.#listener = listener;
|
|
326
326
|
this.#input.setRawMode?.(true);
|
|
@@ -383,12 +383,12 @@ class TextPrompt extends Prompt {
|
|
|
383
383
|
summary(width) {
|
|
384
384
|
return this.style.clip(`${this.style.accent(ANSWERED)} ${this.title} ${this.style.accent(this.#value)}`, width);
|
|
385
385
|
}
|
|
386
|
-
handle(
|
|
386
|
+
handle(key) {
|
|
387
387
|
this.#error = "";
|
|
388
|
-
switch (
|
|
388
|
+
switch (key.name) {
|
|
389
389
|
case KeyName.Char:
|
|
390
|
-
this.#value = this.#value.slice(0, this.#at) +
|
|
391
|
-
this.#at +=
|
|
390
|
+
this.#value = this.#value.slice(0, this.#at) + key.char + this.#value.slice(this.#at);
|
|
391
|
+
this.#at += key.char.length;
|
|
392
392
|
return;
|
|
393
393
|
case KeyName.Space:
|
|
394
394
|
this.#error = "A space is not usable here.";
|
|
@@ -454,8 +454,8 @@ class ConfirmPrompt extends Prompt {
|
|
|
454
454
|
const answer = this.#value ? "yes" : "no";
|
|
455
455
|
return this.style.clip(`${this.style.accent(ANSWERED)} ${this.title} ${this.style.accent(answer)}`, width);
|
|
456
456
|
}
|
|
457
|
-
handle(
|
|
458
|
-
const typed =
|
|
457
|
+
handle(key) {
|
|
458
|
+
const typed = key.char.toLowerCase();
|
|
459
459
|
if (typed === "y") {
|
|
460
460
|
this.finish(true);
|
|
461
461
|
return;
|
|
@@ -464,11 +464,11 @@ class ConfirmPrompt extends Prompt {
|
|
|
464
464
|
this.finish(false);
|
|
465
465
|
return;
|
|
466
466
|
}
|
|
467
|
-
if (
|
|
467
|
+
if (key.name === KeyName.Left || key.name === KeyName.Right || key.name === KeyName.Tab || key.name === KeyName.Space) {
|
|
468
468
|
this.#value = !this.#value;
|
|
469
469
|
return;
|
|
470
470
|
}
|
|
471
|
-
if (
|
|
471
|
+
if (key.name === KeyName.Enter)
|
|
472
472
|
this.finish(this.#value);
|
|
473
473
|
}
|
|
474
474
|
}
|
|
@@ -557,8 +557,8 @@ class SelectPrompt extends Prompt {
|
|
|
557
557
|
const count = this.items.length;
|
|
558
558
|
this.#cursor = (this.#cursor + by + count) % count;
|
|
559
559
|
}
|
|
560
|
-
handle(
|
|
561
|
-
switch (
|
|
560
|
+
handle(key) {
|
|
561
|
+
switch (key.name) {
|
|
562
562
|
case KeyName.Up:
|
|
563
563
|
case KeyName.ShiftTab:
|
|
564
564
|
this.#move(-1);
|
|
@@ -585,7 +585,7 @@ class SelectPrompt extends Prompt {
|
|
|
585
585
|
this.finish(this.#ordered());
|
|
586
586
|
return;
|
|
587
587
|
case KeyName.Char:
|
|
588
|
-
this.#type(
|
|
588
|
+
this.#type(key.char);
|
|
589
589
|
return;
|
|
590
590
|
default:
|
|
591
591
|
return;
|
|
@@ -619,13 +619,13 @@ class DirectoryPrompt extends TextPrompt {
|
|
|
619
619
|
|
|
620
620
|
class PackageNamePrompt extends TextPrompt {
|
|
621
621
|
validate(value) {
|
|
622
|
-
return
|
|
622
|
+
return isValidPackageName2(value) ? undefined : "npm forbids uppercase, and a leading dot or underscore.";
|
|
623
623
|
}
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
class FeaturePrompt extends SelectPrompt {
|
|
627
627
|
constructor(style, initial) {
|
|
628
|
-
super(style, "Features",
|
|
628
|
+
super(style, "Features", FEATURES2.map((feature) => ({
|
|
629
629
|
value: feature.name,
|
|
630
630
|
label: feature.name,
|
|
631
631
|
hint: feature.summary
|
|
@@ -680,14 +680,14 @@ class Wizard {
|
|
|
680
680
|
if (defaults.name !== undefined)
|
|
681
681
|
return defaults.name;
|
|
682
682
|
const derived = basename(resolve(defaults.cwd, target));
|
|
683
|
-
if (
|
|
683
|
+
if (isValidPackageName2(derived))
|
|
684
684
|
return derived;
|
|
685
685
|
return this.#runner.ask(new PackageNamePrompt(this.#style, "Package name", slug(derived)));
|
|
686
686
|
}
|
|
687
687
|
async#force(defaults, target) {
|
|
688
688
|
if (defaults.force)
|
|
689
689
|
return true;
|
|
690
|
-
const blocking =
|
|
690
|
+
const blocking = blockingEntries2(resolve(defaults.cwd, target));
|
|
691
691
|
if (blocking.length === 0)
|
|
692
692
|
return false;
|
|
693
693
|
const shown = blocking.slice(0, 3).join(", ");
|
|
@@ -774,7 +774,7 @@ var byAsking = async () => {
|
|
|
774
774
|
var interactive = values.yes !== true && ProcessTty.available();
|
|
775
775
|
try {
|
|
776
776
|
const options = interactive ? await byAsking() : withoutAsking();
|
|
777
|
-
const result = await
|
|
777
|
+
const result = await scaffold2(options);
|
|
778
778
|
const where = relative(process.cwd(), result.directory);
|
|
779
779
|
console.log(where === "" ? `
|
|
780
780
|
Created ${result.name} here` : `
|
|
@@ -791,7 +791,7 @@ Created ${result.name} in ${where}/`);
|
|
|
791
791
|
const as = implied.length === 1 ? "a requirement" : "requirements";
|
|
792
792
|
console.log(` ${implied.join(", ")} came along as ${as}`);
|
|
793
793
|
}
|
|
794
|
-
const services =
|
|
794
|
+
const services = FEATURES2.filter((feature) => result.features.includes(feature.name) && feature.service !== undefined);
|
|
795
795
|
for (const feature of services) {
|
|
796
796
|
console.log(` ${feature.name} needs ${feature.service} to do anything`);
|
|
797
797
|
}
|
|
@@ -807,7 +807,7 @@ Created ${result.name} in ${where}/`);
|
|
|
807
807
|
console.log(style.muted(error.message));
|
|
808
808
|
process.exit(130);
|
|
809
809
|
}
|
|
810
|
-
if (error instanceof
|
|
810
|
+
if (error instanceof ScaffoldError2)
|
|
811
811
|
fail(error.message);
|
|
812
812
|
throw error;
|
|
813
813
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
3
|
+
FEATURES2,
|
|
4
|
+
featureNames2,
|
|
5
|
+
TEMPLATES2,
|
|
6
|
+
VERSION_PLACEHOLDER2,
|
|
7
|
+
blockingEntries2,
|
|
8
|
+
ScaffoldError2,
|
|
9
|
+
isValidPackageName2,
|
|
10
|
+
scaffold2
|
|
11
|
+
} from "./chunk-szd4jhfn.js";
|
|
12
12
|
export {
|
|
13
|
-
FEATURES,
|
|
14
|
-
ScaffoldError,
|
|
15
|
-
TEMPLATES,
|
|
16
|
-
VERSION_PLACEHOLDER,
|
|
17
|
-
blockingEntries,
|
|
18
|
-
featureNames,
|
|
19
|
-
isValidPackageName,
|
|
20
|
-
scaffold
|
|
13
|
+
FEATURES2 as FEATURES,
|
|
14
|
+
ScaffoldError2 as ScaffoldError,
|
|
15
|
+
TEMPLATES2 as TEMPLATES,
|
|
16
|
+
VERSION_PLACEHOLDER2 as VERSION_PLACEHOLDER,
|
|
17
|
+
blockingEntries2 as blockingEntries,
|
|
18
|
+
featureNames2 as featureNames,
|
|
19
|
+
isValidPackageName2 as isValidPackageName,
|
|
20
|
+
scaffold2 as scaffold
|
|
21
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dunx/create-app",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Scaffold a new dunx application - bunx @dunx/create-app my-api",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@types/bun": ">=1.
|
|
53
|
+
"@types/bun": ">=1.4.1"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"@types/bun": {
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
61
|
-
"bun": ">=1.4.
|
|
61
|
+
"bun": ">=1.4.1"
|
|
62
62
|
}
|
|
63
63
|
}
|