@pwfabric/cli 0.0.0-stage → 1.0.0-rc.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 +202 -0
- package/README.md +122 -2
- package/dist/args.d.ts +12 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +43 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +10 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/add.d.ts +4 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +56 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/build.d.ts +4 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +55 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/create.d.ts +10 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +119 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +13 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +107 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/lib/flags.d.ts +11 -0
- package/dist/commands/lib/flags.d.ts.map +1 -0
- package/dist/commands/lib/flags.js +33 -0
- package/dist/commands/lib/flags.js.map +1 -0
- package/dist/commands/lib/identity.d.ts +39 -0
- package/dist/commands/lib/identity.d.ts.map +1 -0
- package/dist/commands/lib/identity.js +120 -0
- package/dist/commands/lib/identity.js.map +1 -0
- package/dist/commands/lib/project.d.ts +35 -0
- package/dist/commands/lib/project.d.ts.map +1 -0
- package/dist/commands/lib/project.js +78 -0
- package/dist/commands/lib/project.js.map +1 -0
- package/dist/commands/lib/report.d.ts +16 -0
- package/dist/commands/lib/report.d.ts.map +1 -0
- package/dist/commands/lib/report.js +75 -0
- package/dist/commands/lib/report.js.map +1 -0
- package/dist/commands/lib/starter.d.ts +42 -0
- package/dist/commands/lib/starter.d.ts.map +1 -0
- package/dist/commands/lib/starter.js +136 -0
- package/dist/commands/lib/starter.js.map +1 -0
- package/dist/commands/lib/static-server.d.ts +46 -0
- package/dist/commands/lib/static-server.d.ts.map +1 -0
- package/dist/commands/lib/static-server.js +173 -0
- package/dist/commands/lib/static-server.js.map +1 -0
- package/dist/commands/pack.d.ts +6 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +56 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +16 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/run.d.ts +15 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +79 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/types.d.ts +35 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +10 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +33 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/dev/assemble.d.ts +48 -0
- package/dist/dev/assemble.d.ts.map +1 -0
- package/dist/dev/assemble.js +339 -0
- package/dist/dev/assemble.js.map +1 -0
- package/dist/dev/compile.d.ts +55 -0
- package/dist/dev/compile.d.ts.map +1 -0
- package/dist/dev/compile.js +215 -0
- package/dist/dev/compile.js.map +1 -0
- package/dist/dev/csp.d.ts +68 -0
- package/dist/dev/csp.d.ts.map +1 -0
- package/dist/dev/csp.js +260 -0
- package/dist/dev/csp.js.map +1 -0
- package/dist/dev/diagnostics.d.ts +22 -0
- package/dist/dev/diagnostics.d.ts.map +1 -0
- package/dist/dev/diagnostics.js +22 -0
- package/dist/dev/diagnostics.js.map +1 -0
- package/dist/dev/envelope.d.ts +93 -0
- package/dist/dev/envelope.d.ts.map +1 -0
- package/dist/dev/envelope.js +154 -0
- package/dist/dev/envelope.js.map +1 -0
- package/dist/dev/media.d.ts +54 -0
- package/dist/dev/media.d.ts.map +1 -0
- package/dist/dev/media.js +128 -0
- package/dist/dev/media.js.map +1 -0
- package/dist/dev/needs-host.d.ts +3 -0
- package/dist/dev/needs-host.d.ts.map +1 -0
- package/dist/dev/needs-host.js +32 -0
- package/dist/dev/needs-host.js.map +1 -0
- package/dist/dev/output.d.ts +10 -0
- package/dist/dev/output.d.ts.map +1 -0
- package/dist/dev/output.js +32 -0
- package/dist/dev/output.js.map +1 -0
- package/dist/dev/overlay.d.ts +22 -0
- package/dist/dev/overlay.d.ts.map +1 -0
- package/dist/dev/overlay.js +59 -0
- package/dist/dev/overlay.js.map +1 -0
- package/dist/dev/server.d.ts +28 -0
- package/dist/dev/server.d.ts.map +1 -0
- package/dist/dev/server.js +264 -0
- package/dist/dev/server.js.map +1 -0
- package/dist/dev/shell.d.ts +83 -0
- package/dist/dev/shell.d.ts.map +1 -0
- package/dist/dev/shell.js +244 -0
- package/dist/dev/shell.js.map +1 -0
- package/dist/dev/sources.d.ts +46 -0
- package/dist/dev/sources.d.ts.map +1 -0
- package/dist/dev/sources.js +165 -0
- package/dist/dev/sources.js.map +1 -0
- package/dist/dev/theme.d.ts +52 -0
- package/dist/dev/theme.d.ts.map +1 -0
- package/dist/dev/theme.js +185 -0
- package/dist/dev/theme.js.map +1 -0
- package/dist/dev/types.d.ts +41 -0
- package/dist/dev/types.d.ts.map +1 -0
- package/dist/dev/types.js +11 -0
- package/dist/dev/types.js.map +1 -0
- package/dist/dev/watcher.d.ts +30 -0
- package/dist/dev/watcher.d.ts.map +1 -0
- package/dist/dev/watcher.js +150 -0
- package/dist/dev/watcher.js.map +1 -0
- package/dist/host/definitions.d.ts +62 -0
- package/dist/host/definitions.d.ts.map +1 -0
- package/dist/host/definitions.js +136 -0
- package/dist/host/definitions.js.map +1 -0
- package/dist/host/http.d.ts +40 -0
- package/dist/host/http.d.ts.map +1 -0
- package/dist/host/http.js +156 -0
- package/dist/host/http.js.map +1 -0
- package/dist/host/local-host.d.ts +60 -0
- package/dist/host/local-host.d.ts.map +1 -0
- package/dist/host/local-host.js +420 -0
- package/dist/host/local-host.js.map +1 -0
- package/dist/host/oidc.d.ts +47 -0
- package/dist/host/oidc.d.ts.map +1 -0
- package/dist/host/oidc.js +192 -0
- package/dist/host/oidc.js.map +1 -0
- package/dist/host/query.d.ts +36 -0
- package/dist/host/query.d.ts.map +1 -0
- package/dist/host/query.js +158 -0
- package/dist/host/query.js.map +1 -0
- package/dist/host/receipts.d.ts +26 -0
- package/dist/host/receipts.d.ts.map +1 -0
- package/dist/host/receipts.js +72 -0
- package/dist/host/receipts.js.map +1 -0
- package/dist/host/records.d.ts +74 -0
- package/dist/host/records.d.ts.map +1 -0
- package/dist/host/records.js +229 -0
- package/dist/host/records.js.map +1 -0
- package/dist/host/tokens.d.ts +29 -0
- package/dist/host/tokens.d.ts.map +1 -0
- package/dist/host/tokens.js +52 -0
- package/dist/host/tokens.js.map +1 -0
- package/dist/host/types.d.ts +33 -0
- package/dist/host/types.d.ts.map +1 -0
- package/dist/host/types.js +11 -0
- package/dist/host/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -3
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type PackFolder, type PackIssue, type PackValidation } from '@pwfabric/pack';
|
|
2
|
+
import type { CommandIO } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Checks every `packs[]` pin against `.pwf/packs/<id>@<version>/`.
|
|
5
|
+
* A build that is not cached is a warning (`PIN_NOT_CACHED`: `pwf add` it);
|
|
6
|
+
* a cached build whose content hash differs from the pin is an error
|
|
7
|
+
* (`PIN_HASH_MISMATCH`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function checkPins(root: string, identity: PackValidation['identity']): Promise<PackIssue[]>;
|
|
10
|
+
/** `validatePack` plus {@link checkPins}, as one result. */
|
|
11
|
+
export declare function validateProject(root: string, pack: PackFolder): Promise<PackValidation>;
|
|
12
|
+
/** Prints issues grouped by severity, errors first. Prints nothing for an empty list. */
|
|
13
|
+
export declare function printIssues(io: CommandIO, issues: readonly PackIssue[]): void;
|
|
14
|
+
/** `n errors, n warnings` for a summary line. */
|
|
15
|
+
export declare function countLine(issues: readonly PackIssue[]): string;
|
|
16
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/commands/lib/report.ts"],"names":[],"mappings":"AAKA,OAAO,EAA0B,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC7G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA+BxG;AAED,4DAA4D;AAC5D,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAK7F;AAKD,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,IAAI,CAQ7E;AAED,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAI9D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation as the commands report it: the pack library's findings plus
|
|
3
|
+
* the project's pins checked against its local cache.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { hashPack, validatePack } from '@pwfabric/pack';
|
|
7
|
+
import { cacheDir, cacheRelDir, readCachedPack } from './project.js';
|
|
8
|
+
import { pinsOf } from './identity.js';
|
|
9
|
+
/**
|
|
10
|
+
* Checks every `packs[]` pin against `.pwf/packs/<id>@<version>/`.
|
|
11
|
+
* A build that is not cached is a warning (`PIN_NOT_CACHED`: `pwf add` it);
|
|
12
|
+
* a cached build whose content hash differs from the pin is an error
|
|
13
|
+
* (`PIN_HASH_MISMATCH`).
|
|
14
|
+
*/
|
|
15
|
+
export async function checkPins(root, identity) {
|
|
16
|
+
const issues = [];
|
|
17
|
+
for (const pin of pinsOf(identity)) {
|
|
18
|
+
let dir;
|
|
19
|
+
try {
|
|
20
|
+
dir = cacheDir(root, pin.id, pin.version);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
issues.push({ severity: 'error', code: 'PIN_INVALID', path: 'pwpack.json', message: e.message });
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const rel = cacheRelDir(pin.id, pin.version);
|
|
27
|
+
if (!existsSync(dir)) {
|
|
28
|
+
issues.push({
|
|
29
|
+
severity: 'warning',
|
|
30
|
+
code: 'PIN_NOT_CACHED',
|
|
31
|
+
path: rel,
|
|
32
|
+
message: `${pin.id}@${pin.version} is pinned but not in ${rel}; run \`pwf add <its .pwpack or folder>\``,
|
|
33
|
+
});
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const actual = hashPack(await readCachedPack(dir));
|
|
37
|
+
if (actual !== pin.hash) {
|
|
38
|
+
issues.push({
|
|
39
|
+
severity: 'error',
|
|
40
|
+
code: 'PIN_HASH_MISMATCH',
|
|
41
|
+
path: rel,
|
|
42
|
+
message: `${pin.id}@${pin.version} is pinned at ${pin.hash} but the cached build hashes ${actual}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return issues;
|
|
47
|
+
}
|
|
48
|
+
/** `validatePack` plus {@link checkPins}, as one result. */
|
|
49
|
+
export async function validateProject(root, pack) {
|
|
50
|
+
const result = validatePack(pack);
|
|
51
|
+
const pinIssues = await checkPins(root, result.identity);
|
|
52
|
+
const issues = [...result.issues, ...pinIssues];
|
|
53
|
+
return { ...result, issues, ok: !issues.some((i) => i.severity === 'error') };
|
|
54
|
+
}
|
|
55
|
+
const SEVERITIES = ['error', 'warning', 'info'];
|
|
56
|
+
const HEADINGS = { error: 'Errors', warning: 'Warnings', info: 'Notes' };
|
|
57
|
+
/** Prints issues grouped by severity, errors first. Prints nothing for an empty list. */
|
|
58
|
+
export function printIssues(io, issues) {
|
|
59
|
+
for (const severity of SEVERITIES) {
|
|
60
|
+
const group = issues.filter((i) => i.severity === severity);
|
|
61
|
+
if (group.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
const write = severity === 'error' ? io.err.bind(io) : io.out.bind(io);
|
|
64
|
+
write(`${HEADINGS[severity]} (${group.length}):`);
|
|
65
|
+
for (const issue of group)
|
|
66
|
+
write(` ${issue.code}${issue.path ? ` ${issue.path}` : ''}: ${issue.message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** `n errors, n warnings` for a summary line. */
|
|
70
|
+
export function countLine(issues) {
|
|
71
|
+
const n = (s) => issues.filter((i) => i.severity === s).length;
|
|
72
|
+
const plural = (count, word) => `${count} ${word}${count === 1 ? '' : 's'}`;
|
|
73
|
+
return `${plural(n('error'), 'error')}, ${plural(n('warning'), 'warning')}`;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/lib/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `pwf create` writes: the starter app's documents, composed only from
|
|
3
|
+
* the block types and themes the foundation pack actually carries.
|
|
4
|
+
*/
|
|
5
|
+
import type { PackFolder, PackValidation } from '@pwfabric/pack';
|
|
6
|
+
export interface FoundationBlock {
|
|
7
|
+
/** Block type a receipt names (the manifest's `name`). */
|
|
8
|
+
readonly type: string;
|
|
9
|
+
/** Atom id, `<category>.<name>`. */
|
|
10
|
+
readonly id: string;
|
|
11
|
+
/** Prop names the manifest declares. */
|
|
12
|
+
readonly props: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export interface FoundationCatalog {
|
|
15
|
+
readonly blocks: readonly FoundationBlock[];
|
|
16
|
+
/** Theme ids (`ui-appearance` atoms). */
|
|
17
|
+
readonly themes: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Block types and themes of a pack, from its derived atoms. A block's type is
|
|
21
|
+
* the `name` of the `manifest.json` next to its component (falling back to the
|
|
22
|
+
* last segment of its id); its props are the manifest's `definition.props`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function catalogOf(pack: PackFolder, validation: PackValidation): FoundationCatalog;
|
|
25
|
+
export interface BlockNode {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly type: string;
|
|
28
|
+
readonly props: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/** Starter blocks for the home page, using only block types the catalog has. */
|
|
31
|
+
export declare function starterBlocks(catalog: FoundationCatalog, title: string): BlockNode[];
|
|
32
|
+
/** The theme the starter uses: `theme-zinc` when present (a neutral default), otherwise the first by id. */
|
|
33
|
+
export declare function starterTheme(catalog: FoundationCatalog): string | undefined;
|
|
34
|
+
/** `my-shop` → `My Shop`. */
|
|
35
|
+
export declare function titleOf(name: string): string;
|
|
36
|
+
export declare function starterPlan(name: string, title: string, blocks: readonly BlockNode[], foundationId: string, theme: string | undefined): unknown;
|
|
37
|
+
export declare function starterAppearance(theme: string | undefined): unknown;
|
|
38
|
+
export declare function starterNavigation(): unknown;
|
|
39
|
+
export declare function starterReceipt(blocks: readonly BlockNode[]): unknown;
|
|
40
|
+
export declare const ATOMS_README_TEXT = "# atoms/\n\nThis app's own reusable parts. Empty to start: the app is composed from the\nfoundation pack pinned in `pwpack.json`.\n\nAdd a block as `atoms/blocks/<category>/<name>/component.tsx` with a\n`manifest.json` next to it; see the pwpack format and block manifest\ndocuments of the PWFabric specification for every atom family.\n\nThis README is documentation, not an atom: it travels with the pack and\nvalidation notes it as such (DOC_FILE).\n";
|
|
41
|
+
export declare const GITIGNORE_TEXT = ".pwf/\n*.pwpack\n";
|
|
42
|
+
//# sourceMappingURL=starter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starter.d.ts","sourceRoot":"","sources":["../../../src/commands/lib/starter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGhE,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAC3C,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC;AAYD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,GAAG,iBAAiB,CAsBzF;AAuBD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACxC;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,CAYpF;AAED,4GAA4G;AAC5G,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAG3E;AAED,6BAA6B;AAC7B,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM5C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CA6B/I;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAEpE;AAED,eAAO,MAAM,iBAAiB,0cAW7B,CAAA;AAED,eAAO,MAAM,cAAc,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { stripBom } from './identity.js';
|
|
2
|
+
function parseObject(bytes) {
|
|
3
|
+
if (!bytes)
|
|
4
|
+
return null;
|
|
5
|
+
try {
|
|
6
|
+
const v = JSON.parse(stripBom(new TextDecoder().decode(bytes)));
|
|
7
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v) ? v : null;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Block types and themes of a pack, from its derived atoms. A block's type is
|
|
15
|
+
* the `name` of the `manifest.json` next to its component (falling back to the
|
|
16
|
+
* last segment of its id); its props are the manifest's `definition.props`.
|
|
17
|
+
*/
|
|
18
|
+
export function catalogOf(pack, validation) {
|
|
19
|
+
const blocks = [];
|
|
20
|
+
const themes = [];
|
|
21
|
+
for (const atom of validation.atoms) {
|
|
22
|
+
if (atom.kind === 'ui-appearance') {
|
|
23
|
+
const manifest = parseObject(pack.files.get(atom.relPath));
|
|
24
|
+
themes.push(typeof manifest?.id === 'string' ? manifest.id : atom.id);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (atom.kind !== 'block')
|
|
28
|
+
continue;
|
|
29
|
+
const dir = atom.relPath.slice(0, atom.relPath.lastIndexOf('/') + 1);
|
|
30
|
+
const manifest = parseObject(pack.files.get(`${dir}manifest.json`));
|
|
31
|
+
const name = typeof manifest?.name === 'string' ? manifest.name : atom.id.split('.').pop();
|
|
32
|
+
const definition = manifest?.definition;
|
|
33
|
+
const props = Array.isArray(definition?.props)
|
|
34
|
+
? definition.props.flatMap((p) => p !== null && typeof p === 'object' && typeof p.name === 'string' ? [p.name] : [])
|
|
35
|
+
: [];
|
|
36
|
+
blocks.push({ type: name, id: atom.id, props });
|
|
37
|
+
}
|
|
38
|
+
return { blocks, themes };
|
|
39
|
+
}
|
|
40
|
+
/** The starter page, in order: a heading, a paragraph and a button. */
|
|
41
|
+
const SLOTS = [
|
|
42
|
+
{ id: 'title', types: ['heading', 'title'], textProps: ['text', 'content', 'title', 'label'], text: (t) => t, extra: { level: 'h1' } },
|
|
43
|
+
{
|
|
44
|
+
id: 'intro',
|
|
45
|
+
types: ['text', 'paragraph', 'prose'],
|
|
46
|
+
textProps: ['content', 'text', 'body', 'markdown'],
|
|
47
|
+
text: () => 'Edit app/surfaces/home.receipt.json to change this page, then run pwf dev to see it.',
|
|
48
|
+
extra: {},
|
|
49
|
+
},
|
|
50
|
+
{ id: 'cta', types: ['button'], textProps: ['label', 'text'], text: () => 'Get started', extra: { href: '/' } },
|
|
51
|
+
];
|
|
52
|
+
/** Starter blocks for the home page, using only block types the catalog has. */
|
|
53
|
+
export function starterBlocks(catalog, title) {
|
|
54
|
+
const out = [];
|
|
55
|
+
for (const slot of SLOTS) {
|
|
56
|
+
const block = slot.types.map((t) => catalog.blocks.find((b) => b.type === t)).find((b) => b !== undefined);
|
|
57
|
+
if (!block)
|
|
58
|
+
continue;
|
|
59
|
+
const props = {};
|
|
60
|
+
const textProp = slot.textProps.find((p) => block.props.includes(p));
|
|
61
|
+
if (textProp)
|
|
62
|
+
props[textProp] = slot.text(title);
|
|
63
|
+
for (const [k, v] of Object.entries(slot.extra))
|
|
64
|
+
if (block.props.includes(k))
|
|
65
|
+
props[k] = v;
|
|
66
|
+
out.push({ id: slot.id, type: block.type, props });
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
/** The theme the starter uses: `theme-zinc` when present (a neutral default), otherwise the first by id. */
|
|
71
|
+
export function starterTheme(catalog) {
|
|
72
|
+
if (catalog.themes.includes('theme-zinc'))
|
|
73
|
+
return 'theme-zinc';
|
|
74
|
+
return [...catalog.themes].sort()[0];
|
|
75
|
+
}
|
|
76
|
+
/** `my-shop` → `My Shop`. */
|
|
77
|
+
export function titleOf(name) {
|
|
78
|
+
return name
|
|
79
|
+
.split(/[-_]+/)
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.map((w) => w[0]?.toUpperCase() + w.slice(1))
|
|
82
|
+
.join(' ');
|
|
83
|
+
}
|
|
84
|
+
export function starterPlan(name, title, blocks, foundationId, theme) {
|
|
85
|
+
return {
|
|
86
|
+
title: title.slice(0, 80),
|
|
87
|
+
intent: {
|
|
88
|
+
purpose: `${title}: describe what this app is for`,
|
|
89
|
+
audience: 'Describe who will use it',
|
|
90
|
+
tone: 'Clear and friendly',
|
|
91
|
+
successCriteria: 'The home page renders',
|
|
92
|
+
},
|
|
93
|
+
theme: { direction: 'Clean and neutral', paletteHint: theme ?? 'the foundation default', status: 'applied' },
|
|
94
|
+
capabilities: [],
|
|
95
|
+
media: [],
|
|
96
|
+
customBlocks: [],
|
|
97
|
+
surfaces: [
|
|
98
|
+
{
|
|
99
|
+
key: 'home',
|
|
100
|
+
name: 'Home',
|
|
101
|
+
isEntry: true,
|
|
102
|
+
purpose: `The first page of ${name}`,
|
|
103
|
+
keyContent: blocks.map((b) => b.id),
|
|
104
|
+
linksTo: [],
|
|
105
|
+
usesCapabilities: [],
|
|
106
|
+
usesMedia: [],
|
|
107
|
+
usesCustomBlocks: [],
|
|
108
|
+
status: 'applied',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
packs: [{ id: foundationId }],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function starterAppearance(theme) {
|
|
115
|
+
return theme ? { use: theme } : { config: { mode: { policy: 'light' } } };
|
|
116
|
+
}
|
|
117
|
+
export function starterNavigation() {
|
|
118
|
+
return { navbar: { links: [{ label: 'Home', href: '/' }] } };
|
|
119
|
+
}
|
|
120
|
+
export function starterReceipt(blocks) {
|
|
121
|
+
return { title: 'Home', blocks };
|
|
122
|
+
}
|
|
123
|
+
export const ATOMS_README_TEXT = `# atoms/
|
|
124
|
+
|
|
125
|
+
This app's own reusable parts. Empty to start: the app is composed from the
|
|
126
|
+
foundation pack pinned in \`pwpack.json\`.
|
|
127
|
+
|
|
128
|
+
Add a block as \`atoms/blocks/<category>/<name>/component.tsx\` with a
|
|
129
|
+
\`manifest.json\` next to it; see the pwpack format and block manifest
|
|
130
|
+
documents of the PWFabric specification for every atom family.
|
|
131
|
+
|
|
132
|
+
This README is documentation, not an atom: it travels with the pack and
|
|
133
|
+
validation notes it as such (DOC_FILE).
|
|
134
|
+
`;
|
|
135
|
+
export const GITIGNORE_TEXT = `.pwf/\n*.pwpack\n`;
|
|
136
|
+
//# sourceMappingURL=starter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"starter.js","sourceRoot":"","sources":["../../../src/commands/lib/starter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const CONTENT_TYPES: Readonly<Record<string, string>>;
|
|
2
|
+
export declare function contentTypeOf(path: string): string;
|
|
3
|
+
/** Where the files come from: a folder on disk, or files held in memory (an opened archive). */
|
|
4
|
+
export type StaticSource = {
|
|
5
|
+
readonly dir: string;
|
|
6
|
+
} | {
|
|
7
|
+
readonly files: ReadonlyMap<string, Uint8Array>;
|
|
8
|
+
};
|
|
9
|
+
export interface StaticServerOptions {
|
|
10
|
+
readonly source: StaticSource;
|
|
11
|
+
/** 0 picks a free port. */
|
|
12
|
+
readonly port: number;
|
|
13
|
+
/** Default 127.0.0.1. */
|
|
14
|
+
readonly hostname?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface StaticServer {
|
|
17
|
+
readonly url: string;
|
|
18
|
+
readonly port: number;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/** The request path as a safe relative POSIX path, or null when it is malformed or escapes the root. */
|
|
22
|
+
export declare function requestPath(rawUrl: string): string | null;
|
|
23
|
+
/** Resolves a request to a file: the path itself, `<path>/index.html`, then the SPA fallback for page paths. */
|
|
24
|
+
export declare function resolveRequest(source: StaticSource, rel: string): Promise<{
|
|
25
|
+
path: string;
|
|
26
|
+
body: Uint8Array;
|
|
27
|
+
} | null>;
|
|
28
|
+
/** The static-host headers file a build writes beside `index.html`. */
|
|
29
|
+
export declare const HEADERS_FILE = "_headers";
|
|
30
|
+
/** One rule of a `_headers` file: a path pattern and the headers it adds. */
|
|
31
|
+
export interface HeaderRule {
|
|
32
|
+
readonly pattern: string;
|
|
33
|
+
readonly headers: readonly (readonly [string, string])[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parses the `_headers` convention of static hosts: a line that starts at
|
|
37
|
+
* column 0 is a path pattern (`/*`, `/assets/*`, `/about`), the indented
|
|
38
|
+
* `Name: value` lines under it are the headers it adds. `#` lines are
|
|
39
|
+
* comments.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseHeadersFile(text: string): HeaderRule[];
|
|
42
|
+
/** Whether a `_headers` pattern matches a request path (`/` + the relative path). */
|
|
43
|
+
export declare function headerPatternMatches(pattern: string, path: string): boolean;
|
|
44
|
+
/** Starts the server; resolves once it is listening. */
|
|
45
|
+
export declare function startStaticServer(options: StaticServerOptions): Promise<StaticServer>;
|
|
46
|
+
//# sourceMappingURL=static-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-server.d.ts","sourceRoot":"","sources":["../../../src/commands/lib/static-server.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB1D,CAAA;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAAE,CAAA;AAEzG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yBAAyB;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,wGAAwG;AACxG,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAezD;AAYD,gHAAgH;AAChH,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,IAAI,CAAC,CAS1H;AAID,uEAAuE;AACvE,eAAO,MAAM,YAAY,aAAa,CAAA;AAEtC,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;CACzD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAa3D;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG3E;AAoCD,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBrF"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small static file server for a built pwapp: correct content types, no
|
|
3
|
+
* directory listings, no path escapes, and an SPA fallback to `index.html`
|
|
4
|
+
* for page paths.
|
|
5
|
+
*/
|
|
6
|
+
import { createServer } from 'node:http';
|
|
7
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
8
|
+
import { extname, join, resolve, sep } from 'node:path';
|
|
9
|
+
export const CONTENT_TYPES = {
|
|
10
|
+
'.html': 'text/html; charset=utf-8',
|
|
11
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
12
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
13
|
+
'.json': 'application/json; charset=utf-8',
|
|
14
|
+
'.css': 'text/css; charset=utf-8',
|
|
15
|
+
'.svg': 'image/svg+xml',
|
|
16
|
+
'.map': 'application/json; charset=utf-8',
|
|
17
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
18
|
+
'.png': 'image/png',
|
|
19
|
+
'.jpg': 'image/jpeg',
|
|
20
|
+
'.jpeg': 'image/jpeg',
|
|
21
|
+
'.gif': 'image/gif',
|
|
22
|
+
'.webp': 'image/webp',
|
|
23
|
+
'.avif': 'image/avif',
|
|
24
|
+
'.ico': 'image/x-icon',
|
|
25
|
+
'.woff': 'font/woff',
|
|
26
|
+
'.woff2': 'font/woff2',
|
|
27
|
+
'.wasm': 'application/wasm',
|
|
28
|
+
};
|
|
29
|
+
export function contentTypeOf(path) {
|
|
30
|
+
return CONTENT_TYPES[extname(path).toLowerCase()] ?? 'application/octet-stream';
|
|
31
|
+
}
|
|
32
|
+
/** The request path as a safe relative POSIX path, or null when it is malformed or escapes the root. */
|
|
33
|
+
export function requestPath(rawUrl) {
|
|
34
|
+
let pathname;
|
|
35
|
+
try {
|
|
36
|
+
pathname = decodeURIComponent(new URL(rawUrl, 'http://localhost').pathname);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (pathname.includes('\0') || pathname.includes('\\'))
|
|
42
|
+
return null;
|
|
43
|
+
const parts = [];
|
|
44
|
+
for (const seg of pathname.split('/')) {
|
|
45
|
+
if (seg === '' || seg === '.')
|
|
46
|
+
continue;
|
|
47
|
+
if (seg === '..')
|
|
48
|
+
return null;
|
|
49
|
+
parts.push(seg);
|
|
50
|
+
}
|
|
51
|
+
return parts.join('/');
|
|
52
|
+
}
|
|
53
|
+
async function load(source, rel) {
|
|
54
|
+
if ('files' in source)
|
|
55
|
+
return source.files.get(rel) ?? null;
|
|
56
|
+
const root = resolve(source.dir);
|
|
57
|
+
const abs = resolve(join(root, ...rel.split('/')));
|
|
58
|
+
if (abs !== root && !abs.startsWith(root + sep))
|
|
59
|
+
return null;
|
|
60
|
+
const st = await stat(abs).catch(() => null);
|
|
61
|
+
if (!st?.isFile())
|
|
62
|
+
return null;
|
|
63
|
+
return new Uint8Array(await readFile(abs));
|
|
64
|
+
}
|
|
65
|
+
/** Resolves a request to a file: the path itself, `<path>/index.html`, then the SPA fallback for page paths. */
|
|
66
|
+
export async function resolveRequest(source, rel) {
|
|
67
|
+
const candidates = rel === '' ? ['index.html'] : [rel, `${rel}/index.html`];
|
|
68
|
+
// A path whose last segment has no extension is a page path: answer it with the shell.
|
|
69
|
+
if (rel !== '' && extname(rel) === '')
|
|
70
|
+
candidates.push('index.html');
|
|
71
|
+
for (const path of candidates) {
|
|
72
|
+
const body = await load(source, path);
|
|
73
|
+
if (body)
|
|
74
|
+
return { path, body };
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const TEXT = { 'content-type': 'text/plain; charset=utf-8' };
|
|
79
|
+
/** The static-host headers file a build writes beside `index.html`. */
|
|
80
|
+
export const HEADERS_FILE = '_headers';
|
|
81
|
+
/**
|
|
82
|
+
* Parses the `_headers` convention of static hosts: a line that starts at
|
|
83
|
+
* column 0 is a path pattern (`/*`, `/assets/*`, `/about`), the indented
|
|
84
|
+
* `Name: value` lines under it are the headers it adds. `#` lines are
|
|
85
|
+
* comments.
|
|
86
|
+
*/
|
|
87
|
+
export function parseHeadersFile(text) {
|
|
88
|
+
const rules = [];
|
|
89
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
90
|
+
if (!raw.trim() || raw.trim().startsWith('#'))
|
|
91
|
+
continue;
|
|
92
|
+
if (!/^\s/.test(raw)) {
|
|
93
|
+
rules.push({ pattern: raw.trim(), headers: [] });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const at = raw.indexOf(':');
|
|
97
|
+
const rule = rules[rules.length - 1];
|
|
98
|
+
if (at > 0 && rule)
|
|
99
|
+
rule.headers.push([raw.slice(0, at).trim(), raw.slice(at + 1).trim()]);
|
|
100
|
+
}
|
|
101
|
+
return rules;
|
|
102
|
+
}
|
|
103
|
+
/** Whether a `_headers` pattern matches a request path (`/` + the relative path). */
|
|
104
|
+
export function headerPatternMatches(pattern, path) {
|
|
105
|
+
if (pattern.endsWith('*'))
|
|
106
|
+
return path.startsWith(pattern.slice(0, -1));
|
|
107
|
+
return pattern === path;
|
|
108
|
+
}
|
|
109
|
+
/** The headers the `_headers` file adds for a relative path. */
|
|
110
|
+
async function extraHeaders(source, rel) {
|
|
111
|
+
const out = {};
|
|
112
|
+
const file = await load(source, HEADERS_FILE);
|
|
113
|
+
if (!file)
|
|
114
|
+
return out;
|
|
115
|
+
for (const rule of parseHeadersFile(new TextDecoder().decode(file))) {
|
|
116
|
+
if (!headerPatternMatches(rule.pattern, `/${rel}`))
|
|
117
|
+
continue;
|
|
118
|
+
for (const [name, value] of rule.headers)
|
|
119
|
+
out[name.toLowerCase()] = value;
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
async function handle(source, req, res) {
|
|
124
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
125
|
+
res.writeHead(405, { ...TEXT, allow: 'GET, HEAD' }).end('method not allowed\n');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const rel = requestPath(req.url ?? '/');
|
|
129
|
+
// The headers file configures the server; it is not part of the site.
|
|
130
|
+
const found = rel === null || rel === HEADERS_FILE ? null : await resolveRequest(source, rel);
|
|
131
|
+
if (!found) {
|
|
132
|
+
res.writeHead(404, TEXT).end('not found\n');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
res.writeHead(200, {
|
|
136
|
+
...(await extraHeaders(source, rel ?? '')),
|
|
137
|
+
'content-type': contentTypeOf(found.path),
|
|
138
|
+
'content-length': String(found.body.byteLength),
|
|
139
|
+
'cache-control': 'no-cache',
|
|
140
|
+
});
|
|
141
|
+
if (req.method === 'HEAD')
|
|
142
|
+
res.end();
|
|
143
|
+
else
|
|
144
|
+
res.end(found.body);
|
|
145
|
+
}
|
|
146
|
+
/** Starts the server; resolves once it is listening. */
|
|
147
|
+
export function startStaticServer(options) {
|
|
148
|
+
const hostname = options.hostname ?? '127.0.0.1';
|
|
149
|
+
const server = createServer((req, res) => {
|
|
150
|
+
handle(options.source, req, res).catch(() => {
|
|
151
|
+
if (!res.headersSent)
|
|
152
|
+
res.writeHead(500, TEXT);
|
|
153
|
+
res.end('internal error\n');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
return new Promise((resolveStart, reject) => {
|
|
157
|
+
server.once('error', reject);
|
|
158
|
+
server.listen(options.port, hostname, () => {
|
|
159
|
+
server.off('error', reject);
|
|
160
|
+
const { port } = server.address();
|
|
161
|
+
const host = hostname.includes(':') ? `[${hostname}]` : hostname;
|
|
162
|
+
resolveStart({
|
|
163
|
+
url: `http://${host}:${port}/`,
|
|
164
|
+
port,
|
|
165
|
+
close: () => new Promise((done, fail) => {
|
|
166
|
+
server.closeAllConnections();
|
|
167
|
+
server.close((err) => (err ? fail(err) : done()));
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=static-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-server.js","sourceRoot":"","sources":["../../../src/commands/lib/static-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Command, CommandIO, ParsedArgs } from './types.js';
|
|
2
|
+
/** `<name>-<version>.pwpack`, where name is the last segment of the pack id. */
|
|
3
|
+
export declare function archiveName(id: string, version: string): string;
|
|
4
|
+
export declare function runPack(args: ParsedArgs, io: CommandIO): Promise<number>;
|
|
5
|
+
export declare const pack: Command;
|
|
6
|
+
//# sourceMappingURL=pack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAKhE,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B9E;AAED,eAAO,MAAM,IAAI,EAAE,OAclB,CAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pwf pack [dir]` — the deterministic `.pwpack` archive of a valid folder.
|
|
3
|
+
*/
|
|
4
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { hashPack, packContent, writePwpack } from '@pwfabric/pack';
|
|
7
|
+
import { guard, stringFlag } from './lib/flags.js';
|
|
8
|
+
import { readProject, resolveFrom } from './lib/project.js';
|
|
9
|
+
import { countLine, printIssues, validateProject } from './lib/report.js';
|
|
10
|
+
/** `<name>-<version>.pwpack`, where name is the last segment of the pack id. */
|
|
11
|
+
export function archiveName(id, version) {
|
|
12
|
+
const name = id.split('/').pop()?.replace(/^@/, '') || 'pack';
|
|
13
|
+
return `${name}-${version}.pwpack`;
|
|
14
|
+
}
|
|
15
|
+
export async function runPack(args, io) {
|
|
16
|
+
const root = resolveFrom(io.cwd, args.positionals[0]);
|
|
17
|
+
const pack = await readProject(root);
|
|
18
|
+
const result = await validateProject(root, pack);
|
|
19
|
+
if (!result.ok || !result.identity) {
|
|
20
|
+
printIssues(io, result.issues);
|
|
21
|
+
io.err(`pwf pack: ${root} is not valid (${countLine(result.issues)}); nothing written`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
printIssues(io, result.issues.filter((i) => i.severity === 'warning'));
|
|
25
|
+
const { id, version } = result.identity;
|
|
26
|
+
const outFlag = stringFlag(args, 'out');
|
|
27
|
+
const out = outFlag ? resolveFrom(io.cwd, outFlag) : join(root, archiveName(id, version));
|
|
28
|
+
// The archive carries the pack content only: an author's tooling never
|
|
29
|
+
// ships, and the archive hashes the same as the folder it came from.
|
|
30
|
+
const content = packContent(pack);
|
|
31
|
+
const bytes = await writePwpack(content);
|
|
32
|
+
await mkdir(dirname(out), { recursive: true });
|
|
33
|
+
await writeFile(out, bytes);
|
|
34
|
+
const left = pack.files.size - content.files.size;
|
|
35
|
+
io.out(`Packed ${id}@${version}`);
|
|
36
|
+
io.out(` file ${out}`);
|
|
37
|
+
io.out(` size ${bytes.byteLength} bytes, ${content.files.size} files${left > 0 ? ` (${left} outside the pack content left out)` : ''}`);
|
|
38
|
+
io.out(` hash ${hashPack(content)}`);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
export const pack = {
|
|
42
|
+
name: 'pack',
|
|
43
|
+
summary: 'Write the deterministic .pwpack archive of a folder',
|
|
44
|
+
usage: `pwf pack [dir] [--out <file>]
|
|
45
|
+
|
|
46
|
+
dir the pwpack folder (default: the current folder)
|
|
47
|
+
--out <file> where to write (default <dir>/<name>-<version>.pwpack)
|
|
48
|
+
|
|
49
|
+
Validates first and refuses on errors. The archive holds the pack content
|
|
50
|
+
only — pwpack.json, LICENSE, NOTICE, README.md, app/, atoms/ and media/ —
|
|
51
|
+
never .pwf/, .gitignore or the author's tooling (package.json, scripts/, …).
|
|
52
|
+
The same folder always gives the same bytes; the printed hash is the
|
|
53
|
+
content hash pins use.`,
|
|
54
|
+
run: (args, io) => guard('pack', io, () => runPack(args, io)),
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=pack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Command } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every `pwf` command. Lanes add their command module here and nowhere else.
|
|
4
|
+
* Order is the order `pwf help` prints.
|
|
5
|
+
*/
|
|
6
|
+
export declare const COMMANDS: Command[];
|
|
7
|
+
export declare function findCommand(name: string): Command | undefined;
|
|
8
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/commands/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AASzC;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAO,EAAiE,CAAA;AAE/F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAE7D"}
|