@mondaydotcomorg/z2h-cli 0.1.0 → 0.1.1
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/commands/__tests__/create-workspace.test.d.ts +2 -0
- package/dist/commands/__tests__/create-workspace.test.d.ts.map +1 -0
- package/dist/commands/__tests__/create.test.d.ts +2 -0
- package/dist/commands/__tests__/create.test.d.ts.map +1 -0
- package/dist/commands/create-workspace.d.ts +5 -0
- package/dist/commands/create-workspace.d.ts.map +1 -0
- package/dist/commands/create-workspace.js +80 -0
- package/dist/commands/create.d.ts +7 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +97 -0
- package/dist/constants.d.ts +1 -14
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -34
- package/dist/esm/commands/__tests__/create-workspace.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/create-workspace.test.d.ts.map +1 -0
- package/dist/esm/commands/__tests__/create.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/create.test.d.ts.map +1 -0
- package/dist/esm/commands/create-workspace.d.ts +5 -0
- package/dist/esm/commands/create-workspace.d.ts.map +1 -0
- package/dist/esm/commands/create-workspace.mjs +74 -0
- package/dist/esm/commands/create.d.ts +7 -0
- package/dist/esm/commands/create.d.ts.map +1 -0
- package/dist/esm/commands/create.mjs +91 -0
- package/dist/esm/constants.d.ts +1 -14
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +11 -32
- package/dist/esm/index.mjs +28 -0
- package/dist/esm/shadow/__tests__/consumer-pkg.test.d.ts +2 -0
- package/dist/esm/shadow/__tests__/consumer-pkg.test.d.ts.map +1 -0
- package/dist/esm/shadow/__tests__/merge-package-json.test.d.ts +2 -0
- package/dist/esm/shadow/__tests__/merge-package-json.test.d.ts.map +1 -0
- package/dist/esm/shadow/consumer-pkg.d.ts +5 -15
- package/dist/esm/shadow/consumer-pkg.d.ts.map +1 -1
- package/dist/esm/shadow/consumer-pkg.mjs +11 -72
- package/dist/esm/shadow/merge-package-json.d.ts +10 -4
- package/dist/esm/shadow/merge-package-json.d.ts.map +1 -1
- package/dist/esm/shadow/merge-package-json.mjs +12 -11
- package/dist/esm/shadow/sync.mjs +2 -2
- package/dist/esm/templates/app/claude-settings.mjs +10 -0
- package/dist/esm/types.d.ts +0 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/util/__tests__/templates.test.d.ts +2 -0
- package/dist/esm/util/__tests__/templates.test.d.ts.map +1 -0
- package/dist/esm/util/__tests__/workspace-templates-shipped.test.d.ts +2 -0
- package/dist/esm/util/__tests__/workspace-templates-shipped.test.d.ts.map +1 -0
- package/dist/esm/util/__tests__/workspace.test.d.ts +2 -0
- package/dist/esm/util/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/esm/util/s3/upload.mjs +1 -1
- package/dist/esm/util/templates.d.ts +22 -0
- package/dist/esm/util/templates.d.ts.map +1 -0
- package/dist/esm/util/templates.mjs +36 -0
- package/dist/esm/util/workspace.d.ts +20 -0
- package/dist/esm/util/workspace.d.ts.map +1 -0
- package/dist/esm/util/workspace.mjs +46 -0
- package/dist/index.js +28 -0
- package/dist/shadow/__tests__/consumer-pkg.test.d.ts +2 -0
- package/dist/shadow/__tests__/consumer-pkg.test.d.ts.map +1 -0
- package/dist/shadow/__tests__/merge-package-json.test.d.ts +2 -0
- package/dist/shadow/__tests__/merge-package-json.test.d.ts.map +1 -0
- package/dist/shadow/consumer-pkg.d.ts +5 -15
- package/dist/shadow/consumer-pkg.d.ts.map +1 -1
- package/dist/shadow/consumer-pkg.js +10 -72
- package/dist/shadow/merge-package-json.d.ts +10 -4
- package/dist/shadow/merge-package-json.d.ts.map +1 -1
- package/dist/shadow/merge-package-json.js +11 -10
- package/dist/shadow/sync.js +2 -2
- package/dist/templates/app/claude-settings.js +13 -0
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/util/__tests__/templates.test.d.ts +2 -0
- package/dist/util/__tests__/templates.test.d.ts.map +1 -0
- package/dist/util/__tests__/workspace-templates-shipped.test.d.ts +2 -0
- package/dist/util/__tests__/workspace-templates-shipped.test.d.ts.map +1 -0
- package/dist/util/__tests__/workspace.test.d.ts +2 -0
- package/dist/util/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/util/s3/upload.js +1 -1
- package/dist/util/templates.d.ts +22 -0
- package/dist/util/templates.d.ts.map +1 -0
- package/dist/util/templates.js +45 -0
- package/dist/util/workspace.d.ts +20 -0
- package/dist/util/workspace.d.ts.map +1 -0
- package/dist/util/workspace.js +57 -0
- package/package.json +5 -3
- package/src/commands/__tests__/create-workspace.test.ts +78 -0
- package/src/commands/__tests__/create.test.ts +111 -0
- package/src/commands/create-workspace.ts +85 -0
- package/src/commands/create.ts +113 -0
- package/src/constants.ts +11 -34
- package/src/index.ts +28 -0
- package/src/shadow/__tests__/consumer-pkg.test.ts +56 -0
- package/src/shadow/__tests__/merge-package-json.test.ts +44 -0
- package/src/shadow/consumer-pkg.ts +10 -88
- package/src/shadow/merge-package-json.ts +12 -11
- package/src/shadow/sync.ts +2 -2
- package/src/templates/app/CLAUDE.md +72 -0
- package/src/templates/app/claude-settings.json +7 -0
- package/src/templates/app/default-index.tsx.tmpl +21 -0
- package/src/templates/app/gitignore +4 -0
- package/src/templates/app/html-index.tsx.tmpl +21 -0
- package/src/templates/app/package.json.tmpl +13 -0
- package/src/templates/workspace/README.md +39 -0
- package/src/templates/workspace/gitignore +23 -0
- package/src/templates/workspace/npmrc +3 -0
- package/src/templates/workspace/nvmrc +1 -0
- package/src/templates/workspace/package.json.tmpl +23 -0
- package/src/templates/workspace/yarn-releases/yarn-4.5.1.cjs +934 -0
- package/src/templates/workspace/yarnrc.yml +7 -0
- package/src/types.ts +4 -1
- package/src/util/__tests__/templates.test.ts +27 -0
- package/src/util/__tests__/workspace-templates-shipped.test.ts +35 -0
- package/src/util/__tests__/workspace.test.ts +65 -0
- package/src/util/s3/upload.ts +1 -1
- package/src/util/templates.ts +37 -0
- package/src/util/workspace.ts +52 -0
package/src/types.ts
CHANGED
|
@@ -17,12 +17,15 @@ export interface ConsumerPkg {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// ─────────── Shadow pkg (generated by CLI, lives at .zth/package.json) ───
|
|
20
|
+
// Runtime deps come from the workspace root via yarn's workspace hoisting.
|
|
21
|
+
// `devDependencies` declares the toolchain the shadow directly executes
|
|
22
|
+
// (trident-toolkit) so yarn wires its bin onto the shadow's script PATH.
|
|
23
|
+
// No federation `shared` config in this stack, so no peerDependencies.
|
|
20
24
|
export interface ShadowPkg {
|
|
21
25
|
name: string;
|
|
22
26
|
version: string;
|
|
23
27
|
private: true;
|
|
24
28
|
scripts: Record<string, string>;
|
|
25
|
-
peerDependencies: Record<string, string>;
|
|
26
29
|
devDependencies: Record<string, string>;
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { renderTemplate } from '../templates';
|
|
3
|
+
|
|
4
|
+
describe('renderTemplate', () => {
|
|
5
|
+
it('substitutes a single placeholder', () => {
|
|
6
|
+
expect(renderTemplate('hello __NAME__', { __NAME__: 'world' })).toBe('hello world');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('substitutes the same placeholder multiple times', () => {
|
|
10
|
+
const out = renderTemplate('__X__ + __X__ = double __X__', { __X__: 'a' });
|
|
11
|
+
expect(out).toBe('a + a = double a');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('substitutes multiple distinct placeholders', () => {
|
|
15
|
+
const out = renderTemplate('__A__/__B__', { __A__: 'foo', __B__: 'bar' });
|
|
16
|
+
expect(out).toBe('foo/bar');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('leaves unknown placeholders alone', () => {
|
|
20
|
+
expect(renderTemplate('__X__ __Y__', { __X__: 'set' })).toBe('set __Y__');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('escapes regex-special chars in placeholder values', () => {
|
|
24
|
+
// A value containing $1, &, etc. should be inserted literally.
|
|
25
|
+
expect(renderTemplate('val=__V__', { __V__: '$1 & co' })).toBe('val=$1 & co');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { pathExists, readFile } from 'fs-extra';
|
|
4
|
+
import { getTemplatesDir } from '../templates';
|
|
5
|
+
|
|
6
|
+
describe('workspace templates ship with the package', () => {
|
|
7
|
+
const expected = [
|
|
8
|
+
'workspace/package.json.tmpl',
|
|
9
|
+
'workspace/gitignore',
|
|
10
|
+
'workspace/yarnrc.yml',
|
|
11
|
+
'workspace/nvmrc',
|
|
12
|
+
'workspace/npmrc',
|
|
13
|
+
'workspace/README.md',
|
|
14
|
+
'workspace/yarn-releases/yarn-4.5.1.cjs',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
for (const rel of expected) {
|
|
18
|
+
it(`includes ${rel}`, async () => {
|
|
19
|
+
const full = path.join(getTemplatesDir(), rel);
|
|
20
|
+
expect(await pathExists(full), full).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it('workspace package template carries the z2hWorkspace marker and the ["*", "*/.zth"] glob', async () => {
|
|
25
|
+
const raw = await readFile(path.join(getTemplatesDir(), 'workspace', 'package.json.tmpl'), 'utf8');
|
|
26
|
+
expect(raw).toMatch(/"z2hWorkspace"\s*:\s*true/);
|
|
27
|
+
expect(raw).toMatch(/"\*"/);
|
|
28
|
+
expect(raw).toMatch(/"\*\/\.zth"/);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('workspace yarnrc points yarnPath at the bundled berry release', async () => {
|
|
32
|
+
const raw = await readFile(path.join(getTemplatesDir(), 'workspace', 'yarnrc.yml'), 'utf8');
|
|
33
|
+
expect(raw).toMatch(/yarnPath:\s*\.yarn\/releases\/yarn-4\.5\.1\.cjs/);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { mkdtemp, rm, writeJson, ensureDir } from 'fs-extra';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { getWorkspaceHome, isZ2hWorkspace, assertWorkspace } from '../workspace';
|
|
6
|
+
|
|
7
|
+
describe('workspace util', () => {
|
|
8
|
+
let tmp: string;
|
|
9
|
+
const originalEnv = process.env.Z2H_WORKSPACE_HOME;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
tmp = await mkdtemp(path.join(os.tmpdir(), 'z2h-ws-'));
|
|
13
|
+
process.env.Z2H_WORKSPACE_HOME = tmp;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
if (originalEnv === undefined) {
|
|
18
|
+
delete process.env.Z2H_WORKSPACE_HOME;
|
|
19
|
+
} else {
|
|
20
|
+
process.env.Z2H_WORKSPACE_HOME = originalEnv;
|
|
21
|
+
}
|
|
22
|
+
await rm(tmp, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('getWorkspaceHome respects the env override', () => {
|
|
26
|
+
expect(getWorkspaceHome()).toBe(tmp);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('getWorkspaceHome falls back to ~/zth-projects when no env override', () => {
|
|
30
|
+
delete process.env.Z2H_WORKSPACE_HOME;
|
|
31
|
+
expect(getWorkspaceHome()).toBe(path.join(os.homedir(), 'zth-projects'));
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('isZ2hWorkspace returns false when there is no package.json', async () => {
|
|
35
|
+
expect(await isZ2hWorkspace(tmp)).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('isZ2hWorkspace returns false when package.json lacks the marker', async () => {
|
|
39
|
+
await writeJson(path.join(tmp, 'package.json'), { name: 'something', private: true });
|
|
40
|
+
expect(await isZ2hWorkspace(tmp)).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('isZ2hWorkspace returns true when package.json has z2hWorkspace: true', async () => {
|
|
44
|
+
await writeJson(path.join(tmp, 'package.json'), {
|
|
45
|
+
name: '@mondaydotcomorg/zth-projects-workspace',
|
|
46
|
+
private: true,
|
|
47
|
+
z2hWorkspace: true,
|
|
48
|
+
});
|
|
49
|
+
expect(await isZ2hWorkspace(tmp)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('assertWorkspace throws a helpful error when marker is missing', async () => {
|
|
53
|
+
await ensureDir(tmp);
|
|
54
|
+
await expect(assertWorkspace()).rejects.toThrow(/create-workspace/);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('assertWorkspace resolves and returns the path when marker is present', async () => {
|
|
58
|
+
await writeJson(path.join(tmp, 'package.json'), {
|
|
59
|
+
name: '@mondaydotcomorg/zth-projects-workspace',
|
|
60
|
+
private: true,
|
|
61
|
+
z2hWorkspace: true,
|
|
62
|
+
});
|
|
63
|
+
await expect(assertWorkspace()).resolves.toBe(tmp);
|
|
64
|
+
});
|
|
65
|
+
});
|
package/src/util/s3/upload.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { readFile } from 'fs-extra';
|
|
3
2
|
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import { readFile } from 'fs-extra';
|
|
4
4
|
import { lookup as lookupMime } from 'mime-types';
|
|
5
5
|
import pMap from 'p-map';
|
|
6
6
|
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Substitute `__PLACEHOLDER__` tokens in `content` with values from `vars`.
|
|
6
|
+
* Values are inserted literally — no regex special-char interpretation —
|
|
7
|
+
* which matters for content like `$1` or `&` that could otherwise be
|
|
8
|
+
* captured by `String.prototype.replace`.
|
|
9
|
+
*/
|
|
10
|
+
export function renderTemplate(content: string, vars: Record<string, string>): string {
|
|
11
|
+
let out = content;
|
|
12
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
13
|
+
// Use split+join (literal pattern) to avoid regex interpretation of
|
|
14
|
+
// special chars in `value`.
|
|
15
|
+
out = out.split(key).join(value);
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Absolute path to the bundled `templates/` directory under `src/`.
|
|
22
|
+
*
|
|
23
|
+
* The CLI's `package.json` `files` array ships `src/` (so `src/templates/`
|
|
24
|
+
* lands in published packages). The build emits `.ts` files to `dist/`,
|
|
25
|
+
* but raw template assets (`.tmpl`, `.md`, `gitignore`, `.json`) live only
|
|
26
|
+
* under `src/templates/`. Resolving here keeps a single source of truth
|
|
27
|
+
* for both:
|
|
28
|
+
* - dev (vitest, tsx) → `<pkg>/src/util/` + ../../src/templates → `<pkg>/src/templates`
|
|
29
|
+
* - published install (dist/util) → `<pkg>/dist/util/` + ../../src/templates → `<pkg>/src/templates`
|
|
30
|
+
*/
|
|
31
|
+
export function getTemplatesDir(): string {
|
|
32
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
return path.resolve(here, '..', '..', 'src', 'templates');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type AppTemplate = 'default' | 'html-embed';
|
|
37
|
+
export const APP_TEMPLATES: AppTemplate[] = ['default', 'html-embed'];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { pathExists, readJson } from 'fs-extra';
|
|
4
|
+
|
|
5
|
+
export const WORKSPACE_DIR_NAME = 'zth-projects';
|
|
6
|
+
export const WORKSPACE_MARKER_FIELD = 'z2hWorkspace';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The Z2H workspace home is hardcoded to `~/zth-projects/` for users.
|
|
10
|
+
* Tests override via the `Z2H_WORKSPACE_HOME` env var so they can use a
|
|
11
|
+
* tmp dir without touching the user's real home.
|
|
12
|
+
*/
|
|
13
|
+
export function getWorkspaceHome(): string {
|
|
14
|
+
return process.env.Z2H_WORKSPACE_HOME ?? path.join(os.homedir(), WORKSPACE_DIR_NAME);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface WorkspacePkg {
|
|
18
|
+
[WORKSPACE_MARKER_FIELD]?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns true iff `<dir>/package.json` exists and has `"z2hWorkspace": true`.
|
|
23
|
+
* Any read or parse error returns false (defensive — callers route to a
|
|
24
|
+
* helpful message via assertWorkspace).
|
|
25
|
+
*/
|
|
26
|
+
export async function isZ2hWorkspace(dir: string): Promise<boolean> {
|
|
27
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
28
|
+
if (!(await pathExists(pkgPath))) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const pkg = (await readJson(pkgPath)) as WorkspacePkg;
|
|
33
|
+
return pkg[WORKSPACE_MARKER_FIELD] === true;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolves to the workspace home path if the marker is present; otherwise
|
|
41
|
+
* throws an Error pointing the user at `z2h-cli create-workspace`.
|
|
42
|
+
*/
|
|
43
|
+
export async function assertWorkspace(): Promise<string> {
|
|
44
|
+
const home = getWorkspaceHome();
|
|
45
|
+
if (await isZ2hWorkspace(home)) {
|
|
46
|
+
return home;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(
|
|
49
|
+
`No Z2H workspace at ${home}. Run "z2h-cli create-workspace" first ` +
|
|
50
|
+
`(or set Z2H_WORKSPACE_HOME if you keep the workspace elsewhere).`
|
|
51
|
+
);
|
|
52
|
+
}
|