adjacent-cli 0.1.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -0
  4. package/dist/arguments.d.ts +54 -0
  5. package/dist/arguments.d.ts.map +1 -0
  6. package/dist/arguments.js +68 -0
  7. package/dist/arguments.js.map +1 -0
  8. package/dist/bin.d.ts +3 -0
  9. package/dist/bin.d.ts.map +1 -0
  10. package/dist/bin.js +140 -0
  11. package/dist/bin.js.map +1 -0
  12. package/dist/checks.d.ts +35 -0
  13. package/dist/checks.d.ts.map +1 -0
  14. package/dist/checks.js +206 -0
  15. package/dist/checks.js.map +1 -0
  16. package/dist/create.d.ts +42 -0
  17. package/dist/create.d.ts.map +1 -0
  18. package/dist/create.js +82 -0
  19. package/dist/create.js.map +1 -0
  20. package/dist/dependencies.d.ts +59 -0
  21. package/dist/dependencies.d.ts.map +1 -0
  22. package/dist/dependencies.js +100 -0
  23. package/dist/dependencies.js.map +1 -0
  24. package/dist/destination.d.ts +16 -0
  25. package/dist/destination.d.ts.map +1 -0
  26. package/dist/destination.js +39 -0
  27. package/dist/destination.js.map +1 -0
  28. package/dist/dev-channel.d.ts +40 -0
  29. package/dist/dev-channel.d.ts.map +1 -0
  30. package/dist/dev-channel.js +192 -0
  31. package/dist/dev-channel.js.map +1 -0
  32. package/dist/dev.d.ts +3 -0
  33. package/dist/dev.d.ts.map +1 -0
  34. package/dist/dev.js +12 -0
  35. package/dist/dev.js.map +1 -0
  36. package/dist/doctor.d.ts +46 -0
  37. package/dist/doctor.d.ts.map +1 -0
  38. package/dist/doctor.js +52 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/edits.d.ts +26 -0
  41. package/dist/edits.d.ts.map +1 -0
  42. package/dist/edits.js +101 -0
  43. package/dist/edits.js.map +1 -0
  44. package/dist/index.d.ts +13 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +18 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/init.d.ts +62 -0
  49. package/dist/init.d.ts.map +1 -0
  50. package/dist/init.js +275 -0
  51. package/dist/init.js.map +1 -0
  52. package/dist/keys.d.ts +14 -0
  53. package/dist/keys.d.ts.map +1 -0
  54. package/dist/keys.js +66 -0
  55. package/dist/keys.js.map +1 -0
  56. package/dist/package-manager.d.ts +40 -0
  57. package/dist/package-manager.d.ts.map +1 -0
  58. package/dist/package-manager.js +98 -0
  59. package/dist/package-manager.js.map +1 -0
  60. package/dist/process.d.ts +33 -0
  61. package/dist/process.d.ts.map +1 -0
  62. package/dist/process.js +95 -0
  63. package/dist/process.js.map +1 -0
  64. package/dist/project-name.d.ts +30 -0
  65. package/dist/project-name.d.ts.map +1 -0
  66. package/dist/project-name.js +73 -0
  67. package/dist/project-name.js.map +1 -0
  68. package/dist/reporter.d.ts +12 -0
  69. package/dist/reporter.d.ts.map +1 -0
  70. package/dist/reporter.js +11 -0
  71. package/dist/reporter.js.map +1 -0
  72. package/dist/rewrite.d.ts +54 -0
  73. package/dist/rewrite.d.ts.map +1 -0
  74. package/dist/rewrite.js +262 -0
  75. package/dist/rewrite.js.map +1 -0
  76. package/dist/shutdown.d.ts +24 -0
  77. package/dist/shutdown.d.ts.map +1 -0
  78. package/dist/shutdown.js +67 -0
  79. package/dist/shutdown.js.map +1 -0
  80. package/dist/survey.d.ts +33 -0
  81. package/dist/survey.d.ts.map +1 -0
  82. package/dist/survey.js +94 -0
  83. package/dist/survey.js.map +1 -0
  84. package/dist/template.d.ts +29 -0
  85. package/dist/template.d.ts.map +1 -0
  86. package/dist/template.js +77 -0
  87. package/dist/template.js.map +1 -0
  88. package/dist/ui.d.ts +14 -0
  89. package/dist/ui.d.ts.map +1 -0
  90. package/dist/ui.js +50 -0
  91. package/dist/ui.js.map +1 -0
  92. package/package.json +65 -0
  93. package/templates/adjacent/app/manifest.ts +5 -0
  94. package/templates/adjacent/app/sw.js/route.ts +5 -0
  95. package/templates/adjacent/app.config.ts +21 -0
  96. package/templates/adjacent/components/navigation.tsx +46 -0
  97. package/templates/adjacent/public/apple-touch-icon.png +0 -0
  98. package/templates/adjacent/public/favicon-96x96.png +0 -0
  99. package/templates/adjacent/public/favicon.ico +0 -0
  100. package/templates/adjacent/public/favicon.svg +4 -0
  101. package/templates/adjacent/public/web-app-manifest-192x192.png +0 -0
  102. package/templates/adjacent/public/web-app-manifest-512x512.png +0 -0
  103. package/templates/adjacent/public/web-app-manifest-maskable-192x192.png +0 -0
  104. package/templates/adjacent/public/web-app-manifest-maskable-512x512.png +0 -0
  105. package/templates/starter/app/(app)/layout.tsx +12 -0
  106. package/templates/starter/app/(app)/page.tsx +75 -0
  107. package/templates/starter/app/(app)/settings/page.tsx +24 -0
  108. package/templates/starter/app/(app)/settings/settings-panel.tsx +54 -0
@@ -0,0 +1,95 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function runCommand(command, args, options = {}) {
3
+ return new Promise((resolve, reject) => {
4
+ const child = spawn(command, args, {
5
+ cwd: options.cwd,
6
+ env: options.env,
7
+ stdio: ["ignore", "pipe", "pipe"],
8
+ });
9
+ const stderr = [];
10
+ const stdout = [];
11
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
12
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
13
+ child.once("error", (error) => reject(error));
14
+ child.once("exit", (code) => {
15
+ const result = {
16
+ stderr: Buffer.concat(stderr).toString().trim(),
17
+ stdout: Buffer.concat(stdout).toString().trim(),
18
+ };
19
+ if (code === 0) {
20
+ resolve(result);
21
+ }
22
+ else {
23
+ reject(new Error(`${command} ${args.join(" ")} failed (${code ?? "signal"}): ${result.stderr || result.stdout}`));
24
+ }
25
+ });
26
+ });
27
+ }
28
+ /**
29
+ * Runs a command with its output streamed straight to this terminal, for the
30
+ * long operations where watching progress is the point. `runCommand` captures
31
+ * output instead, which is right for commands whose result is parsed.
32
+ */
33
+ export async function runInheritedCommand(command, args, options = {}) {
34
+ const exitCode = await new Promise((resolve, reject) => {
35
+ const child = spawn(command, args, {
36
+ cwd: options.cwd,
37
+ env: options.env,
38
+ stdio: ["ignore", "inherit", "inherit"],
39
+ });
40
+ child.once("error", (error) => reject(error));
41
+ child.once("exit", (code, signal) => resolve(code ?? (signal ? 1 : 0)));
42
+ });
43
+ if (exitCode !== 0) {
44
+ throw new Error(`${command} ${args.join(" ")} exited with code ${exitCode}.`);
45
+ }
46
+ }
47
+ export function startCommand(command, args, options) {
48
+ return spawn(command, args, {
49
+ cwd: options.cwd,
50
+ detached: options.detached ?? false,
51
+ env: options.env,
52
+ stdio: options.stdio ?? "inherit",
53
+ });
54
+ }
55
+ export function hasExited(child) {
56
+ return child.exitCode !== null || child.signalCode !== null;
57
+ }
58
+ /**
59
+ * `bun run dev` spawns Next.js, which spawns its own workers. Signalling only
60
+ * the direct child leaves that subtree holding the port, so the whole process
61
+ * group is signalled instead.
62
+ */
63
+ export function killProcessTree(child, signal) {
64
+ if (hasExited(child) || child.pid === undefined)
65
+ return;
66
+ try {
67
+ process.kill(-child.pid, signal);
68
+ return;
69
+ }
70
+ catch {
71
+ // Not a group leader, or the group is already gone.
72
+ }
73
+ try {
74
+ child.kill(signal);
75
+ }
76
+ catch {
77
+ // Already gone.
78
+ }
79
+ }
80
+ export async function terminateProcessTree(child, graceMilliseconds = 5_000) {
81
+ if (hasExited(child))
82
+ return;
83
+ const exited = new Promise((resolve) => {
84
+ child.once("exit", () => resolve());
85
+ });
86
+ killProcessTree(child, "SIGTERM");
87
+ const escalation = setTimeout(() => killProcessTree(child, "SIGKILL"), graceMilliseconds);
88
+ try {
89
+ await exited;
90
+ }
91
+ finally {
92
+ clearTimeout(escalation);
93
+ }
94
+ }
95
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The name a generated project is known by, in the several forms the generated
3
+ * files need. Every form is derived from one validated package name so an
4
+ * application cannot be created with a manifest it would fail to validate.
5
+ */
6
+ export interface ProjectIdentity {
7
+ /** Readable title used for the application name and page copy. */
8
+ readonly appName: string;
9
+ /** The npm package name, and the default destination directory. */
10
+ readonly packageName: string;
11
+ /** Bounded to the 12 characters an Adjacent short name allows. */
12
+ readonly shortName: string;
13
+ /** The Adjacent configuration slug, which owns the service worker caches. */
14
+ readonly slug: string;
15
+ }
16
+ /**
17
+ * Accepts the lowercase, hyphen-separated names that are simultaneously a valid
18
+ * npm package name, a valid Adjacent slug, and a safe single path segment.
19
+ */
20
+ export declare function assertProjectName(name: string): string;
21
+ /** "my-todo-app" becomes "My Todo App". */
22
+ export declare function deriveAppName(packageName: string): string;
23
+ /**
24
+ * A short name has to fit 12 characters. The first word is preferred over a
25
+ * truncated title because "My Todo App" reading as "My Todo App" is better than
26
+ * "My Todo App…" and far better than a manifest that fails validation.
27
+ */
28
+ export declare function deriveShortName(appName: string): string;
29
+ export declare function deriveProjectIdentity(name: string): ProjectIdentity;
30
+ //# sourceMappingURL=project-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-name.d.ts","sourceRoot":"","sources":["../src/project-name.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAmBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoCtD;AAMD,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAUnE"}
@@ -0,0 +1,73 @@
1
+ /** Mirrors the slug contract in `adjacent-core`, which the CLI must not import. */
2
+ const PACKAGE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3
+ /** The Adjacent configuration schema caps a short name at 12 characters. */
4
+ const SHORT_NAME_LIMIT = 12;
5
+ /** npm refuses these outright, so a project named for one could never install. */
6
+ const RESERVED_NAMES = new Set(["favicon.ico", "node_modules"]);
7
+ /** A manifest name has to be at least two characters, and so does what derives it. */
8
+ const MIN_LENGTH = 2;
9
+ const MAX_LENGTH = 214;
10
+ function fail(name, reason) {
11
+ throw new Error(`Invalid project name "${name}": ${reason}`);
12
+ }
13
+ /**
14
+ * Accepts the lowercase, hyphen-separated names that are simultaneously a valid
15
+ * npm package name, a valid Adjacent slug, and a safe single path segment.
16
+ */
17
+ export function assertProjectName(name) {
18
+ if (name.trim().length === 0) {
19
+ throw new Error("A project name is required, for example: adj create my-app");
20
+ }
21
+ const value = name.trim();
22
+ if (value.includes("/") || value.includes("\\")) {
23
+ fail(value, "a name cannot contain a path separator. Use --directory to choose where the project is written.");
24
+ }
25
+ if (value === "." || value === ".." || value.startsWith(".")) {
26
+ fail(value, "a name cannot begin with a dot.");
27
+ }
28
+ if (value.length < MIN_LENGTH) {
29
+ fail(value, `a name has to be at least ${MIN_LENGTH} characters, because a web app manifest rejects a shorter one.`);
30
+ }
31
+ if (value.length > MAX_LENGTH) {
32
+ fail(value, `a name cannot be longer than ${MAX_LENGTH} characters.`);
33
+ }
34
+ if (RESERVED_NAMES.has(value)) {
35
+ fail(value, "that name is reserved by npm.");
36
+ }
37
+ if (value !== value.toLowerCase()) {
38
+ fail(value, `a name must be lowercase. Try "${value.toLowerCase()}".`);
39
+ }
40
+ if (!PACKAGE_NAME.test(value)) {
41
+ fail(value, "a name must be lowercase letters and digits separated by single hyphens, for example: my-app.");
42
+ }
43
+ return value;
44
+ }
45
+ function toTitleCase(word) {
46
+ return word.charAt(0).toUpperCase() + word.slice(1);
47
+ }
48
+ /** "my-todo-app" becomes "My Todo App". */
49
+ export function deriveAppName(packageName) {
50
+ return packageName.split("-").map(toTitleCase).join(" ");
51
+ }
52
+ /**
53
+ * A short name has to fit 12 characters. The first word is preferred over a
54
+ * truncated title because "My Todo App" reading as "My Todo App" is better than
55
+ * "My Todo App…" and far better than a manifest that fails validation.
56
+ */
57
+ export function deriveShortName(appName) {
58
+ if (appName.length <= SHORT_NAME_LIMIT)
59
+ return appName;
60
+ const [firstWord = appName] = appName.split(" ");
61
+ return firstWord.slice(0, SHORT_NAME_LIMIT);
62
+ }
63
+ export function deriveProjectIdentity(name) {
64
+ const packageName = assertProjectName(name);
65
+ const appName = deriveAppName(packageName);
66
+ return {
67
+ appName,
68
+ packageName,
69
+ shortName: deriveShortName(appName),
70
+ slug: packageName,
71
+ };
72
+ }
73
+ //# sourceMappingURL=project-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-name.js","sourceRoot":"","sources":["../src/project-name.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /** Everything a command prints, so a caller can silence or capture it. */
2
+ export interface Reporter {
3
+ readonly intro: (message: string) => void;
4
+ readonly outro: (message: string) => void;
5
+ readonly step: (message: string) => void;
6
+ readonly success: (message: string) => void;
7
+ readonly task: <T>(message: string, operation: () => Promise<T>) => Promise<T>;
8
+ }
9
+ export declare const TERMINAL_REPORTER: Reporter;
10
+ /** Used by tests, and by any caller that wants the result rather than the noise. */
11
+ export declare const SILENT_REPORTER: Reporter;
12
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CAChF;AAED,eAAO,MAAM,iBAAiB,EAAE,QAAgD,CAAC;AAEjF,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,QAM7B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { intro, outro, step, success, task } from "./ui.js";
2
+ export const TERMINAL_REPORTER = { intro, outro, step, success, task };
3
+ /** Used by tests, and by any caller that wants the result rather than the noise. */
4
+ export const SILENT_REPORTER = {
5
+ intro: () => undefined,
6
+ outro: () => undefined,
7
+ step: () => undefined,
8
+ success: () => undefined,
9
+ task: (_message, operation) => operation(),
10
+ };
11
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAW5D,MAAM,CAAC,MAAM,iBAAiB,GAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAEjF,oFAAoF;AACpF,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;IACtB,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;IACtB,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS;IACrB,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS;IACxB,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE;CAC3C,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Rewrites of files the application owns. Every rewrite recognises a shape
3
+ * before touching anything: an unfamiliar file is reported with the edit to
4
+ * make by hand rather than guessed at.
5
+ */
6
+ export type RewriteOutcome =
7
+ /** The file already does what Adjacent needs. */
8
+ {
9
+ readonly kind: "unchanged";
10
+ } | {
11
+ readonly contents: string;
12
+ readonly kind: "rewritten";
13
+ }
14
+ /** The shape was not recognised, so the edit is described instead. */
15
+ | {
16
+ readonly instruction: string;
17
+ readonly kind: "manual";
18
+ };
19
+ /** Inserts an import after the last existing one, or at the top of the file. */
20
+ export declare function addImport(source: string, statement: string): string;
21
+ /** The config written when a project has none at all. */
22
+ export declare function createNextConfig(): string;
23
+ /**
24
+ * Wraps the default export in `withAdjacent()`. The recognised shape is
25
+ * `export default <identifier>` or `export default { ... }`, which covers what
26
+ * `create-next-app` writes and most hand-written configs.
27
+ */
28
+ export declare function wrapNextConfig(source: string): RewriteOutcome;
29
+ export interface WrapLayoutOptions {
30
+ /** Import specifier for `app.config`, relative to the layout. */
31
+ readonly configImportPath: string;
32
+ /**
33
+ * True when this layout was just generated by `create-next-app`. Any
34
+ * `metadata` in it is that tool's placeholder rather than the application's,
35
+ * so it is dropped instead of kept.
36
+ */
37
+ readonly scaffolded?: boolean;
38
+ }
39
+ /**
40
+ * Wraps the root layout. Any `metadata` the application already exports is kept
41
+ * and passed through `createAdjacent`, which merges it with the PWA metadata
42
+ * derived from `app.config.ts`, because both cannot be exported at once.
43
+ */
44
+ export declare function wrapRootLayout(source: string, { configImportPath, scaffolded }: WrapLayoutOptions): RewriteOutcome;
45
+ export interface AdjacentStyleOptions {
46
+ readonly tailwind: boolean;
47
+ }
48
+ /**
49
+ * Appends the tokens Adjacent components read. Marked with sentinels so a
50
+ * second run replaces the block rather than appending another copy, and so a
51
+ * token the application already defines is never overwritten.
52
+ */
53
+ export declare function injectAdjacentStyles(source: string, { tailwind }: AdjacentStyleOptions): RewriteOutcome;
54
+ //# sourceMappingURL=rewrite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rewrite.d.ts","sourceRoot":"","sources":["../src/rewrite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,cAAc;AACxB,iDAAiD;AAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAC3D,sEAAsE;GACpE;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAQ9D,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAanE;AAOD,yDAAyD;AACzD,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAsC7D;AAED,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AA8BD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,EAAE,gBAAgB,EAAE,UAAkB,EAAE,EAAE,iBAAiB,GAC1D,cAAc,CAoDhB;AA6GD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GACjC,cAAc,CA8BhB"}
@@ -0,0 +1,262 @@
1
+ const ADJACENT_NEXT = "adjacent-next";
2
+ function hasImportFrom(source, module) {
3
+ return new RegExp(`from\\s+["']${module.replace("/", "\\/")}["']`).test(source);
4
+ }
5
+ /** Inserts an import after the last existing one, or at the top of the file. */
6
+ export function addImport(source, statement) {
7
+ if (source.includes(statement))
8
+ return source;
9
+ // Deliberately not consuming the trailing newlines, so a blank line the
10
+ // author left after their imports survives the insertion.
11
+ const imports = [...source.matchAll(/^import\s[^\n]*;[ \t]*$/gm)];
12
+ const last = imports.at(-1);
13
+ if (last === undefined || last.index === undefined) {
14
+ return `${statement}\n${source}`;
15
+ }
16
+ const end = last.index + last[0].length;
17
+ return `${source.slice(0, end)}\n${statement}${source.slice(end)}`;
18
+ }
19
+ const NEXT_CONFIG_OPTIONS = `{
20
+ connectivityRecovery: true,
21
+ partialPrefetching: true,
22
+ }`;
23
+ /** The config written when a project has none at all. */
24
+ export function createNextConfig() {
25
+ return `import { withAdjacent } from "${ADJACENT_NEXT}";
26
+
27
+ export default withAdjacent(${NEXT_CONFIG_OPTIONS});
28
+ `;
29
+ }
30
+ /**
31
+ * Wraps the default export in `withAdjacent()`. The recognised shape is
32
+ * `export default <identifier>` or `export default { ... }`, which covers what
33
+ * `create-next-app` writes and most hand-written configs.
34
+ */
35
+ export function wrapNextConfig(source) {
36
+ if (source.includes("withAdjacent"))
37
+ return { kind: "unchanged" };
38
+ const identifier = /^export\s+default\s+([A-Za-z_$][\w$]*)\s*;?\s*$/m.exec(source);
39
+ if (identifier?.[1]) {
40
+ const wrapped = source.replace(identifier[0], `export default withAdjacent({\n connectivityRecovery: true,\n partialPrefetching: true,\n ${identifier[1] === "nextConfig" ? "nextConfig" : `nextConfig: ${identifier[1]}`},\n});`);
41
+ return {
42
+ contents: addImport(wrapped, `import { withAdjacent } from "${ADJACENT_NEXT}";`),
43
+ kind: "rewritten",
44
+ };
45
+ }
46
+ const inline = /^export\s+default\s+(\{[\s\S]*\})\s*(?:as\s+\w+\s*)?;?\s*$/m.exec(source);
47
+ if (inline?.[1]) {
48
+ const wrapped = source.replace(inline[0], `export default withAdjacent({\n connectivityRecovery: true,\n partialPrefetching: true,\n nextConfig: ${inline[1]},\n});`);
49
+ return {
50
+ contents: addImport(wrapped, `import { withAdjacent } from "${ADJACENT_NEXT}";`),
51
+ kind: "rewritten",
52
+ };
53
+ }
54
+ return {
55
+ instruction: `Wrap the Next.js config so Adjacent can configure development origins, headers, and package transpilation:\n\n` +
56
+ ` import { withAdjacent } from "${ADJACENT_NEXT}";\n\n` +
57
+ ` export default withAdjacent({\n` +
58
+ ` connectivityRecovery: true,\n` +
59
+ ` partialPrefetching: true,\n` +
60
+ ` nextConfig: yourExistingConfig,\n` +
61
+ ` });`,
62
+ kind: "manual",
63
+ };
64
+ }
65
+ const LAYOUT_INSTRUCTION = (configImportPath) => `Wrap the root layout so Adjacent can supply metadata and inject its browser runtime:\n\n` +
66
+ ` import { createAdjacent, withAdjacentLayout } from "${ADJACENT_NEXT}";\n` +
67
+ ` import config from "${configImportPath}";\n\n` +
68
+ ` const adjacent = createAdjacent(config);\n` +
69
+ ` export const { metadata, viewport } = adjacent;\n\n` +
70
+ ` function RootLayout({ children }) { /* your existing layout */ }\n\n` +
71
+ ` export default withAdjacentLayout(adjacent)(RootLayout);`;
72
+ /**
73
+ * The placeholder `create-next-app` writes. Kept, it would win over everything
74
+ * `app.config.ts` derives, so an application scaffolded as "Photos" would call
75
+ * itself Create Next App in the tab, the share preview and the install prompt.
76
+ */
77
+ const METADATA_TYPE_IMPORT = /^import\s+type\s*\{\s*Metadata\s*\}\s*from\s*"next";\n/m;
78
+ const SCAFFOLDED_METADATA = /^export\s+const\s+metadata(?:\s*:\s*Metadata)?\s*=\s*\{[^{}]*\};?\n+/m;
79
+ /** Removes the placeholder, and the type import it was the only use of. */
80
+ function dropScaffoldedMetadata(source) {
81
+ const without = source.replace(SCAFFOLDED_METADATA, "");
82
+ if (without === source || /\bMetadata\b/.test(without.replace(METADATA_TYPE_IMPORT, ""))) {
83
+ return without;
84
+ }
85
+ return without.replace(METADATA_TYPE_IMPORT, "");
86
+ }
87
+ /**
88
+ * Wraps the root layout. Any `metadata` the application already exports is kept
89
+ * and passed through `createAdjacent`, which merges it with the PWA metadata
90
+ * derived from `app.config.ts`, because both cannot be exported at once.
91
+ */
92
+ export function wrapRootLayout(source, { configImportPath, scaffolded = false }) {
93
+ if (source.includes("withAdjacentLayout"))
94
+ return { kind: "unchanged" };
95
+ const defaultExport = /^export\s+default\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/m.exec(source);
96
+ if (!defaultExport?.[1]) {
97
+ return { instruction: LAYOUT_INSTRUCTION(configImportPath), kind: "manual" };
98
+ }
99
+ const layoutName = defaultExport[1];
100
+ // Only when we scaffolded, because then the metadata is known to be the
101
+ // placeholder. On a project that already exists it is the application's own.
102
+ let contents = scaffolded ? dropScaffoldedMetadata(source) : source;
103
+ // The application's own metadata becomes an input to createAdjacent rather
104
+ // than a second export of the same name.
105
+ const metadataExport = /^export\s+const\s+metadata(\s*:\s*Metadata)?\s*=/m.exec(contents);
106
+ const hasOwnMetadata = metadataExport !== null;
107
+ if (metadataExport) {
108
+ contents = contents.replace(metadataExport[0], `const applicationMetadata${metadataExport[1] ?? ""} =`);
109
+ }
110
+ if (/^export\s+const\s+viewport\b/m.test(contents)) {
111
+ return { instruction: LAYOUT_INSTRUCTION(configImportPath), kind: "manual" };
112
+ }
113
+ contents = contents.replace(defaultExport[0], defaultExport[0].replace(/^export\s+default\s+/, ""));
114
+ contents = addImport(contents, `import { createAdjacent, withAdjacentLayout } from "${ADJACENT_NEXT}";`);
115
+ if (!hasImportFrom(contents, configImportPath)) {
116
+ contents = addImport(contents, `import config from "${configImportPath}";`);
117
+ }
118
+ const creation = hasOwnMetadata
119
+ ? `const adjacent = createAdjacent(config, { metadata: applicationMetadata });`
120
+ : `const adjacent = createAdjacent(config);`;
121
+ return {
122
+ contents: `${contents.trimEnd()}\n\n${creation}\n\nexport const { metadata, viewport } = adjacent;\n\n` +
123
+ `export default withAdjacentLayout(adjacent)(${layoutName});\n`,
124
+ kind: "rewritten",
125
+ };
126
+ }
127
+ const STYLE_START = "/* adjacent:start */";
128
+ const STYLE_END = "/* adjacent:end */";
129
+ /** The design tokens Adjacent components read, beyond what Next.js ships. */
130
+ const ADJACENT_TOKENS = `:root {
131
+ --primary: #171717;
132
+ --primary-foreground: #ffffff;
133
+ --secondary: #f4f4f5;
134
+ --secondary-foreground: #171717;
135
+ --accent: #f4f4f5;
136
+ --accent-foreground: #171717;
137
+ --muted: #f4f4f5;
138
+ --muted-foreground: #71717a;
139
+ --destructive: #b3261e;
140
+ --border: #e4e4e7;
141
+ --ring: #171717;
142
+
143
+ /* The navigation rail is a sidebar, and reads these from 768px up. */
144
+ --sidebar: #fafafa;
145
+ --sidebar-foreground: #171717;
146
+ --sidebar-accent: #e4e4e7;
147
+ --sidebar-accent-foreground: #171717;
148
+
149
+ --radius: 0.625rem;
150
+ --radius-sm: 0.375rem;
151
+ --radius-lg: 0.75rem;
152
+ --radius-full: 9999px;
153
+ }
154
+
155
+ @media (prefers-color-scheme: dark) {
156
+ :root {
157
+ --primary: #fafafa;
158
+ --primary-foreground: #0c0c0e;
159
+ --secondary: #27272a;
160
+ --secondary-foreground: #fafafa;
161
+ --accent: #27272a;
162
+ --accent-foreground: #fafafa;
163
+ --muted: #27272a;
164
+ --muted-foreground: #a1a1aa;
165
+ --destructive: #f2b8b5;
166
+ --border: #27272a;
167
+ --ring: #fafafa;
168
+
169
+ --sidebar: #17171a;
170
+ --sidebar-foreground: #fafafa;
171
+ --sidebar-accent: #27272a;
172
+ --sidebar-accent-foreground: #fafafa;
173
+ }
174
+ }`;
175
+ const TAILWIND_THEME = `@theme inline {
176
+ --color-primary: var(--primary);
177
+ --color-primary-foreground: var(--primary-foreground);
178
+ --color-secondary: var(--secondary);
179
+ --color-secondary-foreground: var(--secondary-foreground);
180
+ --color-accent: var(--accent);
181
+ --color-accent-foreground: var(--accent-foreground);
182
+ --color-muted: var(--muted);
183
+ --color-muted-foreground: var(--muted-foreground);
184
+ --color-destructive: var(--destructive);
185
+ --color-border: var(--border);
186
+ --color-ring: var(--ring);
187
+ --color-sidebar: var(--sidebar);
188
+ --color-sidebar-foreground: var(--sidebar-foreground);
189
+ --color-sidebar-accent: var(--sidebar-accent);
190
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
191
+ }`;
192
+ const SHELL_STYLES = `body {
193
+ /* Keeps iOS from rubber-banding the document out from under fixed chrome. */
194
+ overscroll-behavior-y: none;
195
+ }
196
+
197
+ html {
198
+ /*
199
+ * Anything scrolled to stops above the navigation rather than under it. The
200
+ * shell already reserves the room; this covers an anchor jump, a focused
201
+ * field, and scrollIntoView, which would otherwise ignore it. The same at the
202
+ * top, where a sticky header would otherwise cover what was scrolled to.
203
+ */
204
+ scroll-padding-block-start: var(--adj-header-inset-block-start, 0px);
205
+ scroll-padding-block-end: var(--adj-navigation-inset-block-end, 0px);
206
+ }
207
+
208
+ /*
209
+ * An installed app should not show a browser's scrollbar down its edge. Keyed
210
+ * on a coarse pointer rather than a narrow width, so a touch device is what
211
+ * this hides for and a narrow desktop window keeps the scrollbar it needs.
212
+ * Scrolling itself is untouched: the bar goes, the page still moves.
213
+ */
214
+ @media (pointer: coarse) {
215
+ html {
216
+ /* The standard property, and the one that does the work. */
217
+ scrollbar-width: none;
218
+ }
219
+
220
+ /*
221
+ * For iOS Safari before 18.2 and Chrome before 121, which is a real share of
222
+ * phones. Delete this once the floor is above both and scrollbar-width is
223
+ * enough on its own.
224
+ */
225
+ html::-webkit-scrollbar,
226
+ body::-webkit-scrollbar {
227
+ display: none;
228
+ }
229
+ }`;
230
+ /**
231
+ * Appends the tokens Adjacent components read. Marked with sentinels so a
232
+ * second run replaces the block rather than appending another copy, and so a
233
+ * token the application already defines is never overwritten.
234
+ */
235
+ export function injectAdjacentStyles(source, { tailwind }) {
236
+ const block = [
237
+ STYLE_START,
238
+ "/* Adjacent components read these tokens. Edit them to restyle the app. */",
239
+ ADJACENT_TOKENS,
240
+ ...(tailwind ? [TAILWIND_THEME] : []),
241
+ SHELL_STYLES,
242
+ STYLE_END,
243
+ ].join("\n\n");
244
+ const start = source.indexOf(STYLE_START);
245
+ if (start !== -1) {
246
+ const end = source.indexOf(STYLE_END);
247
+ if (end === -1) {
248
+ return {
249
+ instruction: `The Adjacent block in this stylesheet has a ${STYLE_START} marker but no ` +
250
+ `${STYLE_END} marker, so it cannot be replaced safely. Close the block, or ` +
251
+ `delete both markers and run this again.`,
252
+ kind: "manual",
253
+ };
254
+ }
255
+ const replaced = source.slice(0, start) + block + source.slice(end + STYLE_END.length);
256
+ return replaced === source
257
+ ? { kind: "unchanged" }
258
+ : { contents: replaced, kind: "rewritten" };
259
+ }
260
+ return { contents: `${source.trimEnd()}\n\n${block}\n`, kind: "rewritten" };
261
+ }
262
+ //# sourceMappingURL=rewrite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rewrite.js","sourceRoot":"","sources":["../src/rewrite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export declare const FORCE_EXIT_MILLISECONDS = 5000;
2
+ export interface ShutdownOptions {
3
+ readonly exit: (code: number) => void;
4
+ readonly forceMilliseconds?: number;
5
+ /** Synchronous last-resort kills for anything `release` would have stopped. */
6
+ readonly kill: () => void;
7
+ readonly notify?: (message: string) => void;
8
+ readonly release: () => Promise<void>;
9
+ /** Restores the terminal. Must be synchronous and repeatable. */
10
+ readonly restore: () => void;
11
+ }
12
+ export interface Shutdown {
13
+ readonly listen: () => () => void;
14
+ readonly release: () => Promise<void>;
15
+ readonly request: (code?: number) => void;
16
+ }
17
+ /**
18
+ * A Clack spinner registers a SIGINT listener that only draws a cancel message,
19
+ * which also suppresses Node's default terminate-on-SIGINT. Quitting therefore
20
+ * has to exit explicitly, survive a teardown step that never settles, and stay
21
+ * interruptible so a second interrupt is not silently ignored.
22
+ */
23
+ export declare function createShutdown(options: ShutdownOptions): Shutdown;
24
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../src/shutdown.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,OAAQ,CAAC;AAe7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CAoEjE"}