Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5adfb71
refactor(cli): import calm-shared through its root barrel instead of …
rocketstack-matt Aug 25, 2026
043fc65
refactor(shared): move winston behind a node logger factory so the br…
rocketstack-matt Aug 25, 2026
a4e2b4c
refactor(shared): move the fs-backed document loader factory out of t…
rocketstack-matt Aug 25, 2026
ccd0ae9
feat(shared): add InMemoryDocumentLoader for browser and test consumers
rocketstack-matt Aug 25, 2026
747c24c
refactor(shared): replace net.isIP with a browser-safe IP literal check
rocketstack-matt Aug 25, 2026
5826259
feat(shared): add buildBrowserDocumentLoader composing in-memory, hub…
rocketstack-matt Aug 25, 2026
5cbc01e
refactor(shared): register validation output formatters so junit stay…
rocketstack-matt Aug 25, 2026
7facd75
refactor(shared): split a pure generate core from the file-writing ru…
rocketstack-matt Aug 25, 2026
9597298
refactor(shared): split pure diff and timeline cores from the file-ba…
rocketstack-matt Aug 25, 2026
c0ca5f3
feat(shared): add a browser capability manifest for CLI commands
rocketstack-matt Aug 25, 2026
623aabd
feat(shared): add the @finos/calm-shared/browser entry point and pack…
rocketstack-matt Aug 25, 2026
ac31a32
test(shared): guard the browser entry point with an esbuild bundle an…
rocketstack-matt Aug 25, 2026
6513046
fix(shared): let the browser entry guard clean up its temp dir on fai…
rocketstack-matt Aug 25, 2026
bf046c1
docs(shared): document the browser entry point and the browser-safety…
rocketstack-matt Aug 25, 2026
c9d1aaa
fix(cli): apply module resolution settings inside compilerOptions so …
rocketstack-matt Aug 25, 2026
36a13ab
test(shared): simulate browser globals in the browser entry probe and…
rocketstack-matt Aug 25, 2026
3c3a102
refactor(shared): isolate hub resource types and tidy generate core i…
rocketstack-matt Aug 25, 2026
be19f96
docs(shared): note load-bearing registrations and the browser mainFie…
rocketstack-matt Aug 25, 2026
01225bd
fix(shared): accept IPv6 zone identifiers in the browser-safe ip lite…
rocketstack-matt Aug 25, 2026
7dc2ebb
refactor(shared): move validate into validate-core so process.exit st…
rocketstack-matt Aug 25, 2026
f9a476b
test(shared): probe generate and diff in the browser entry guard and …
rocketstack-matt Aug 25, 2026
76d2ae1
fix(shared): require a colon before an IPv4-mapped tail in the ip lit…
rocketstack-matt Aug 25, 2026
7e27d5a
test(cli): tidy the calm-shared partial mock and state the manifest d…
rocketstack-matt Aug 25, 2026
04ebf46
fix(shared): mark the timeline command unsupported in the browser cap…
rocketstack-matt Aug 25, 2026
31fa46c
fix(shared): reject redirected responses in the browser document loaders
rocketstack-matt Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions cli/src/browser-manifest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import { Command } from 'commander';
import { setupCLI } from './cli';
import { BROWSER_COMMAND_SUPPORT } from '@finos/calm-shared/browser';

function registeredCommandKeys(): string[] {
const program = new Command();
setupCLI(program);
const keys: string[] = [];
for (const command of program.commands) {
if (command.name() === 'hub') {
for (const sub of command.commands) {
keys.push(`hub ${sub.name()}`);
}
} else {
keys.push(command.name());
}
}
return keys.sort();
}

describe('browser capability manifest matches the CLI', () => {
// Granularity: top-level commands plus the `hub` subgroups (`hub pull`, `hub list`, ...);
// `workspace` subcommands are intentionally not enumerated, they're covered by the single
// `workspace` entry.
it('lists every registered command exactly once', () => {
const manifest = BROWSER_COMMAND_SUPPORT.map((entry) => entry.command).sort();
expect(manifest).toEqual(registeredCommandKeys());
});
});
2 changes: 1 addition & 1 deletion cli/src/cli.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { execSync } from 'child_process';
import path from 'path';
import * as fs from 'fs';
import { parseStringPromise } from 'xml2js';
import { expectDirectoryMatch, expectFilesMatch } from '@finos/calm-shared';
import { expectDirectoryMatch, expectFilesMatch } from '../../shared/src/test/file-comparison';
import { installPackedCli, type CliInstall } from './test_helpers/cli-runner';
import { patchJson } from './test_helpers/json-file';
import { STATIC_GETTING_STARTED_MAPPING_PATH } from './test_helpers/getting-started-url-mapping';
Expand Down
6 changes: 2 additions & 4 deletions cli/src/cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ let templateModule: typeof import('./command-helpers/template');
let optionsModule: typeof import('./command-helpers/generate-options');
let diffModule: typeof import('./command-helpers/diff');
let hubCommandsModule: typeof import('./command-helpers/hub-commands');
let _fileSystemDocLoaderModule: typeof import('@finos/calm-shared/dist/document-loader/file-system-document-loader');
let documentLoaderModule: typeof import('../../shared/src/document-loader/document-loader');
let documentLoaderModule: typeof import('../../shared/src/document-loader/node-document-loader');
let setupCLI: typeof import('./cli').setupCLI;
let cliConfigModule: typeof import('./cli-config');

Expand All @@ -32,8 +31,7 @@ describe('CLI Commands', () => {
templateModule = await import('./command-helpers/template');
optionsModule = await import('./command-helpers/generate-options');
diffModule = await import('./command-helpers/diff');
_fileSystemDocLoaderModule = await import('@finos/calm-shared/dist/document-loader/file-system-document-loader');
documentLoaderModule = await import('../../shared/src/document-loader/document-loader');
documentLoaderModule = await import('../../shared/src/document-loader/node-document-loader');

vi.spyOn(calmShared, 'runGenerate').mockResolvedValue(undefined);
vi.spyOn(calmShared.TemplateProcessor.prototype, 'processTemplate').mockResolvedValue(undefined);
Expand Down
2 changes: 1 addition & 1 deletion cli/src/command-helpers/ai-tools.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { initLogger } from '@finos/calm-shared';
import { Logger } from '@finos/calm-shared/src/logger.js';
import { Logger } from '@finos/calm-shared';
import { mkdir, writeFile, readFile, stat } from 'fs/promises';
import { dirname, join, resolve } from 'path';

Expand Down
15 changes: 6 additions & 9 deletions cli/src/command-helpers/hub-commands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ import { runCreateNamespace, runListArchitectures, runListNamespaces,
// We stub the @finos/calm-shared HTTP client so no real HTTP is made, but keep the
// real (pure) document-id-utils helpers that orchestratePush relies on.
vi.mock('@finos/calm-shared', async () => {
const documentIdUtils = await vi.importActual<Record<string, unknown>>('@finos/calm-shared/dist/hub/document-id-utils');
// Real (pure) semver helpers used by pushDocument's version-bump path.
const semver = await vi.importActual('@finos/calm-shared/dist/hub/semver');
// Real (pure) canonical-equality helper used by pushDocument's fail-if-modified path.
const canonical = await vi.importActual('@finos/calm-shared/dist/hub/canonical');
const actual = await vi.importActual<typeof import('@finos/calm-shared')>('@finos/calm-shared');
const mockClient = {
createNamespace: vi.fn(),
listNamespaces: vi.fn(),
Expand All @@ -41,10 +37,11 @@ vi.mock('@finos/calm-shared', async () => {
createControlConfigurationVersion: vi.fn()
};
return {
...documentIdUtils,
extractDocumentMetadata: vi.fn(documentIdUtils['extractDocumentMetadata'] as (...args: unknown[]) => unknown),
...semver,
...canonical,
// Keep all the real (pure) helpers — document-id-utils, semver and canonical — that
// orchestratePush relies on, then override just the HTTP-touching pieces below. The
// vi.fn(...) overrides must come after this spread, or the spread would clobber them.
...actual,
extractDocumentMetadata: vi.fn(actual.extractDocumentMetadata),
CalmHubClient: vi.fn(function () { return mockClient; }),
HubClientError: class HubClientError extends Error {
constructor(public status: number, public error: string, public request: string) {
Expand Down
5 changes: 3 additions & 2 deletions cli/src/command-helpers/workspace/bump.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest';
import { detectChangedResources, bumpWorkspace, canonicalEqual, maxIncrement } from './bump';
import { saveManifest } from './bundle';
import { CalmHubClient, ResourceChangeType } from '@finos/calm-shared/src/hub/calm-hub-client';
import { CalmHubClient, ResourceChangeType } from '@finos/calm-shared';
import { mkdir, writeFile, rm, readFile } from 'fs/promises';
import path from 'path';

vi.mock('@finos/calm-shared/src/logger', () => ({
vi.mock('@finos/calm-shared', async (importOriginal) => ({
...(await importOriginal<typeof import('@finos/calm-shared')>()),
initLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
}));

Expand Down
13 changes: 8 additions & 5 deletions cli/src/command-helpers/workspace/bump.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import { readFile, writeFile } from 'fs/promises';
import { existsSync } from 'fs';
import { loadManifest, resolveFilePath } from './bundle';
import { buildRefRulesFromDiskIds, syncReferences, RefUpdateResult } from './ref-rewrite';
import { CalmHubClient, ResourceChangeType } from '@finos/calm-shared/src/hub/calm-hub-client';
import {
CalmHubClient,
ResourceChangeType,
DocumentMetadata,
extractDocumentMetadata,
constructDocumentId,
} from '@finos/calm-shared/src/hub/document-id-utils';
import { computeSemVerBump, sortSemVer } from '@finos/calm-shared/src/hub/semver';
import { canonicalEqual } from '@finos/calm-shared/src/hub/canonical';
import { initLogger, Logger } from '@finos/calm-shared/src/logger';
computeSemVerBump,
sortSemVer,
canonicalEqual,
initLogger,
Logger,
} from '@finos/calm-shared';

// Re-exported for existing consumers (push.ts, tests) that import it from here.
export { canonicalEqual };
Expand Down
15 changes: 5 additions & 10 deletions cli/src/command-helpers/workspace/commands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,10 @@ vi.mock('../../cli-config', () => ({
loadAuthPlugin: mocks.loadAuthPlugin,
}));

vi.mock('@finos/calm-shared/src/hub/calm-hub-client', () => ({
CalmHubClient: mocks.CalmHubClient,
}));

vi.mock('./document-id-prompt', () => ({
promptForDocumentId: mocks.promptForDocumentId,
}));

vi.mock('@finos/calm-shared/src/hub/document-id-utils', () => ({
isConformantDocumentId: mocks.isConformantDocumentId,
namespaceFromDocumentId: mocks.namespaceFromDocumentId,
}));

vi.mock('fs/promises', async (importOriginal) => {
const actual = await importOriginal<typeof import('fs/promises')>();
return { ...actual, readFile: mocks.readFile, writeFile: mocks.writeFile };
Expand All @@ -116,7 +107,11 @@ vi.mock('@inquirer/prompts', () => ({
input: mocks.input,
}));

vi.mock('@finos/calm-shared/src/logger', () => ({
vi.mock('@finos/calm-shared', async (importOriginal) => ({
...(await importOriginal<typeof import('@finos/calm-shared')>()),
CalmHubClient: mocks.CalmHubClient,
isConformantDocumentId: mocks.isConformantDocumentId,
namespaceFromDocumentId: mocks.namespaceFromDocumentId,
initLogger: () => ({
info: vi.fn(),
warn: vi.fn(),
Expand Down
4 changes: 1 addition & 3 deletions cli/src/command-helpers/workspace/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ import { detectChangedResources, bumpWorkspace } from './bump';
import { runPostBumpValidation } from './post-bump-validate';
import { loadWorkspaceConfig } from './config';
import { findWorkspaceManifestPath, findGitRoot } from '../../workspace-resolver';
import { initLogger, Logger } from '@finos/calm-shared/src/logger';
import { initLogger, Logger, CalmHubClient, ResourceChangeType, isConformantDocumentId, namespaceFromDocumentId } from '@finos/calm-shared';
import { select, input } from '@inquirer/prompts';
import { CALM_DOCUMENT_TYPES_LIST, isValidCalmDocumentType } from '@finos/calm-models/types';
import { CalmHubClient, ResourceChangeType } from '@finos/calm-shared/src/hub/calm-hub-client';
import { isConformantDocumentId, namespaceFromDocumentId } from '@finos/calm-shared/src/hub/document-id-utils';
import { loadCliConfig } from '../../cli-config';
import { resolveCalmHubOptions } from '../hub-commands';

Expand Down
2 changes: 1 addition & 1 deletion cli/src/command-helpers/workspace/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
import type { ResourceChangeType } from '@finos/calm-shared/src/hub/calm-hub-client';
import type { ResourceChangeType } from '@finos/calm-shared';

/**
* Central, repo-level workspace configuration. Committed at
Expand Down
5 changes: 3 additions & 2 deletions cli/src/command-helpers/workspace/document-id-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
isConformantDocumentId,
DocumentMetadata,
ControlDocumentMetadata,
} from '@finos/calm-shared/src/hub/document-id-utils';
import { RESOURCE_TYPES, ResourceType } from '@finos/calm-shared/src/hub/calm-hub-client';
RESOURCE_TYPES,
ResourceType,
} from '@finos/calm-shared';

const DEFAULT_VERSION = '1.0.0';

Expand Down
5 changes: 3 additions & 2 deletions cli/src/command-helpers/workspace/push.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest';
import { pushWorkspaceToHub } from './push';
import { loadManifest, saveManifest } from './bundle';
import { CalmHubClient, HubClientError } from '@finos/calm-shared/src/hub/calm-hub-client';
import { CalmHubClient, HubClientError } from '@finos/calm-shared';
import { mkdir, writeFile, rm } from 'fs/promises';
import path from 'path';
import { existsSync } from 'fs';
Expand All @@ -15,7 +15,8 @@ const makeClient = (
...overrides,
}) as unknown as CalmHubClient;

vi.mock('@finos/calm-shared/src/logger', () => ({
vi.mock('@finos/calm-shared', async (importOriginal) => ({
...(await importOriginal<typeof import('@finos/calm-shared')>()),
initLogger: () => ({
info: vi.fn(),
warn: vi.fn(),
Expand Down
4 changes: 1 addition & 3 deletions cli/src/command-helpers/workspace/push.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
import { loadManifest, saveManifest, resolveFilePath } from './bundle';
import { CalmHubClient } from '@finos/calm-shared/src/hub/calm-hub-client';
import { DocumentMetadata, extractDocumentMetadata } from '@finos/calm-shared/src/hub/document-id-utils';
import { initLogger, Logger } from '@finos/calm-shared/src/logger';
import { CalmHubClient, DocumentMetadata, extractDocumentMetadata, initLogger, Logger } from '@finos/calm-shared';
import { canonicalEqual } from './bump';

const logger: Logger = initLogger(false, 'workspace');
Expand Down
3 changes: 2 additions & 1 deletion cli/src/command-helpers/workspace/ref-rewrite.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import path from 'path';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const loadJson = async (p: string): Promise<any> => JSON.parse(await readFile(p, 'utf8'));

vi.mock('@finos/calm-shared/src/logger', () => ({
vi.mock('@finos/calm-shared', async (importOriginal) => ({
...(await importOriginal<typeof import('@finos/calm-shared')>()),
initLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
}));

Expand Down
2 changes: 1 addition & 1 deletion cli/src/command-helpers/workspace/ref-rewrite.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { readFile, writeFile } from 'fs/promises';
import { existsSync } from 'fs';
import { REFERENCE_PROPERTIES, WorkspaceManifest, resolveFilePath } from './bundle';
import { initLogger, Logger } from '@finos/calm-shared/src/logger';
import { initLogger, Logger } from '@finos/calm-shared';

const logger: Logger = initLogger(false, 'workspace');

Expand Down
2 changes: 1 addition & 1 deletion cli/src/command-helpers/workspace/rm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { initLogger } from '@finos/calm-shared/src/logger';
import { initLogger } from '@finos/calm-shared';
import { loadManifest, saveManifest } from './bundle';

const logger = initLogger(false, 'workspace-rm');
Expand Down
4 changes: 2 additions & 2 deletions cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"extends": "../tsconfig.base.json",
"module": "Preserve",
"moduleResolution": "bundler",
"compilerOptions": {
"module": "Preserve",
"moduleResolution": "bundler",
"strict": true,
"outDir": "dist",
},
Expand Down
Loading
Loading