Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"semver": "^7.5.2",
"sleep-promise": "^9.1.0",
"strip-color": "^0.1.0",
"terminal-link": "^2.0.0",
"tiny-invariant": "^1.3.1",
"ts-morph": "^16.0.0",
"ts-pattern": "^4.3.0",
Expand Down
18 changes: 14 additions & 4 deletions packages/schema/src/cli/actions/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getZenStackPackages,
loadDocument,
requiredPrismaVersion,
showNotification,
} from '../cli-util';
import { PluginRunner, PluginRunnerOptions } from '../plugin-runner';

Expand All @@ -22,6 +23,7 @@ type Options = {
withPlugins?: string[];
withoutPlugins?: string[];
defaultPlugins: boolean;
offline?: boolean;
};

/**
Expand All @@ -48,11 +50,19 @@ export async function generate(projectPath: string, options: Options) {

await runPlugins(options);

if (options.versionCheck) {
// note that we can't run plugins and do version check concurrently because
// plugins are CPU-bound and can cause version check to false timeout
await checkNewVersion();
// note that we can't run online jobs concurrently with plugins because
// plugins are CPU-bound and can cause false timeout
const postJobs: Promise<void>[] = [];

if (options.versionCheck && !options.offline) {
postJobs.push(checkNewVersion());
}

if (!options.offline) {
postJobs.push(showNotification());
}

await Promise.all(postJobs);
}

async function runPlugins(options: Options) {
Expand Down
34 changes: 34 additions & 0 deletions packages/schema/src/cli/cli-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { getDocument, LangiumDocument, LangiumDocuments, linkContentToContainer
import { NodeFileSystem } from 'langium/node';
import path from 'path';
import semver from 'semver';
import terminalLink from 'terminal-link';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { URI } from 'vscode-uri';
import { z } from 'zod';
import { PLUGIN_MODULE_NAME, STD_LIB_MODULE_NAME } from '../language-server/constants';
import { ZModelFormatter } from '../language-server/zmodel-formatter';
import { createZModelServices, ZModelServices } from '../language-server/zmodel-module';
Expand All @@ -20,6 +22,8 @@ import { CliError } from './cli-error';
export const requiredPrismaVersion = '4.8.0';

const CHECK_VERSION_TIMEOUT = 1000;
const FETCH_CLI_CONFIG_TIMEOUT = 500;
const CLI_CONFIG_ENDPOINT = 'https://zenstack.dev/config/cli.json';

/**
* Loads a zmodel document from a file.
Expand Down Expand Up @@ -364,3 +368,33 @@ async function relinkAll(model: Model, services: ZModelServices) {

return newDoc.parseResult.value as Model;
}

export async function showNotification() {
try {
const fetchResult = await fetch(CLI_CONFIG_ENDPOINT, {
headers: { accept: 'application/json' },
signal: AbortSignal.timeout(FETCH_CLI_CONFIG_TIMEOUT),
});

if (!fetchResult.ok) {
return;
}

const data = await fetchResult.json();
const schema = z.object({
notifications: z.array(z.object({ title: z.string(), url: z.string().url(), active: z.boolean() })),
});
const parseResult = schema.safeParse(data);

if (parseResult.success) {
const activeItems = parseResult.data.notifications.filter((item) => item.active);
// return a random active item
if (activeItems.length > 0) {
const item = activeItems[Math.floor(Math.random() * activeItems.length)];
console.log(terminalLink(item.title, item.url));
}
}
} catch {
// noop
}
}
6 changes: 4 additions & 2 deletions packages/schema/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ export function createProgram() {
'pnpm',
]);
const noVersionCheckOption = new Option('--no-version-check', 'do not check for new version');
const noDependencyCheck = new Option('--no-dependency-check', 'do not check if dependencies are installed');
const noDependencyCheckOption = new Option('--no-dependency-check', 'do not check if dependencies are installed');
const offlineOption = new Option('--offline', 'run in offline mode');

program
.command('info')
Expand Down Expand Up @@ -125,7 +126,8 @@ export function createProgram() {
.addOption(new Option('--no-default-plugins', 'do not run default plugins'))
.addOption(new Option('--no-compile', 'do not compile the output of core plugins'))
.addOption(noVersionCheckOption)
.addOption(noDependencyCheck)
.addOption(noDependencyCheckOption)
.addOption(offlineOption)
.action(generateAction);

program
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.