chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:36 +08:00
commit 8e2a6eb840
10194 changed files with 1593658 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# shared
This library was generated with [Nx](https://nx.dev).
+3
View File
@@ -0,0 +1,3 @@
import { baseConfig } from '../../eslint.config.mjs';
export default [...baseConfig];
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@nx/graph-shared",
"version": "0.0.1",
"type": "commonjs",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts"
}
+13
View File
@@ -0,0 +1,13 @@
{
"name": "shared",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "graph/shared/src",
"projectType": "library",
"tags": [],
"// targets": "to see all targets run: nx show project ui-common --web",
"targets": {
"typecheck": {
"dependsOn": ["^typecheck", "nx:build-native"]
}
}
}
+8
View File
@@ -0,0 +1,8 @@
export * from './lib/use-environment-config';
export * from './lib/project-graph-data-service/get-project-graph-data-service';
export * from './lib/external-api-service';
export * from './lib/external-api';
export * from './lib/use-route-constructor';
export * from './lib/fetch-project-graph';
export * from './lib/use-poll';
export * from './lib/app-config';
+15
View File
@@ -0,0 +1,15 @@
export interface AppConfig {
showDebugger: boolean;
showExperimentalFeatures: boolean;
workspaces: WorkspaceData[];
defaultWorkspaceId: string;
}
export interface WorkspaceData {
id: string;
label: string;
projectGraphUrl: string;
taskGraphUrl: string;
taskInputsUrl: string;
sourceMapsUrl: string;
}
@@ -0,0 +1,24 @@
let externalApiService: ExternalApiService | null = null;
export function getExternalApiService() {
if (!externalApiService) {
externalApiService = new ExternalApiService();
}
return externalApiService;
}
export class ExternalApiService {
private subscribers: Set<(event: { type: string; payload?: any }) => void> =
new Set();
postEvent(event: { type: string; payload?: any }) {
this.subscribers.forEach((subscriber) => {
subscriber(event);
});
}
subscribe(callback: (event: { type: string; payload: any }) => void) {
this.subscribers.add(callback);
}
}
+39
View File
@@ -0,0 +1,39 @@
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
export abstract class ExternalApi {
abstract openProjectDetails(projectName: string, targetName?: string): void;
abstract focusProject(projectName: string): void;
abstract selectAllProjects(): void;
abstract showAffectedProjects(): void;
abstract focusTarget(projectName: string, targetName: string): void;
abstract selectAllTargetsByName(targetName: string): void;
abstract enableExperimentalFeatures(): void;
abstract disableExperimentalFeatures(): void;
loadProjectGraph:
| ((url: string) => Promise<ProjectGraphClientResponse>)
| null = null;
loadTaskGraph: ((url: string) => Promise<TaskGraphClientResponse>) | null =
null;
loadExpandedTaskInputs:
| ((taskId: string) => Promise<Record<string, Record<string, string[]>>>)
| null = null;
loadSourceMaps:
| ((url: string) => Promise<Record<string, Record<string, string[]>>>)
| null = null;
graphInteractionEventListener:
| ((event: { type: string; payload: any }) => void | undefined)
| null = null;
}
@@ -0,0 +1,18 @@
import { Params } from 'react-router-dom';
import { AppConfig } from './app-config';
import { ProjectGraphService } from './project-graph-data-service/get-project-graph-data-service';
export async function fetchProjectGraph(
projectGraphService: ProjectGraphService,
params: Readonly<Params<string>>,
appConfig: AppConfig
) {
const selectedWorkspaceId =
params.selectedWorkspaceId ?? appConfig.defaultWorkspaceId;
const projectInfo = appConfig.workspaces.find(
(graph) => graph.id === selectedWorkspaceId
);
return await projectGraphService.getProjectGraph(projectInfo.projectGraphUrl);
}
+24
View File
@@ -0,0 +1,24 @@
// nx-ignore-next-line
import type {
ExpandedTaskInputsReponse,
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import type { AppConfig } from './app-config';
import type { ExternalApi } from './external-api';
export declare global {
interface Window {
exclude: string[];
watch: boolean;
localMode: 'serve' | 'build';
projectGraphResponse?: ProjectGraphClientResponse;
taskGraphResponse?: TaskGraphClientResponse;
expandedTaskInputsResponse?: ExpandedTaskInputsReponse;
sourceMapsResponse?: Record<string, Record<string, string[]>>;
environment: 'dev' | 'watch' | 'release' | 'nx-console';
appConfig: AppConfig;
useXstateInspect: boolean;
externalApi?: ExternalApi;
}
}
@@ -0,0 +1,92 @@
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import { ProjectGraphService } from './get-project-graph-data-service';
export class FetchProjectGraphService implements ProjectGraphService {
private taskInputsUrl: string;
async getHash(): Promise<string> {
const request = new Request('currentHash', { mode: 'no-cors' });
const response = await fetch(request);
return response.json();
}
async getProjectGraph(
url: string,
requestFull = false
): Promise<ProjectGraphClientResponse> {
const requestUrl = requestFull ? `${url}?full=true` : url;
const request = new Request(requestUrl, { mode: 'no-cors' });
const response = await fetch(request);
return response.json();
}
async getTaskGraph(url: string): Promise<TaskGraphClientResponse> {
const request = new Request(url, { mode: 'no-cors' });
const response = await fetch(request);
return response.json();
}
async getSourceMaps(
url: string
): Promise<Record<string, Record<string, string[]>>> {
const request = new Request(url, { mode: 'no-cors' });
const response = await fetch(request);
return response.json();
}
setTaskInputsUrl(url: string) {
this.taskInputsUrl = url;
}
async getSpecificTaskGraph(
url: string,
projects: string[] | null,
targets: string[],
configuration?: string
): Promise<TaskGraphClientResponse> {
const params = new URLSearchParams();
if (projects) {
params.append('projects', projects.join(' '));
}
params.append('targets', targets.join(' '));
if (configuration) {
params.append('configuration', configuration);
}
const request = new Request(`${url}?${params.toString()}`, {
mode: 'no-cors',
});
return await fetch(request).then((res) => res.json());
}
async getExpandedTaskInputs(
taskId: string
): Promise<Record<string, string[]>> {
if (!this.taskInputsUrl) {
return {};
}
const request = new Request(`${this.taskInputsUrl}?taskId=${taskId}`, {
mode: 'no-cors',
});
const response = await fetch(request);
return (await response.json())[taskId];
}
}
@@ -0,0 +1,51 @@
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import { FetchProjectGraphService } from './fetch-project-graph-service';
import { LocalProjectGraphService } from './local-project-graph-service';
import { MockProjectGraphService } from './mock-project-graph-service';
import { NxConsoleProjectGraphService } from './nx-console-project-graph-service';
let projectGraphService: ProjectGraphService;
export interface ProjectGraphService {
getHash: () => Promise<string>;
getProjectGraph: (
url: string,
requestFull?: boolean
) => Promise<ProjectGraphClientResponse>;
getTaskGraph: (url: string) => Promise<TaskGraphClientResponse>;
getSpecificTaskGraph?: (
url: string,
projects: string | string[] | null,
targets: string[],
configuration?: string
) => Promise<TaskGraphClientResponse>;
setTaskInputsUrl?: (url: string) => void;
getExpandedTaskInputs?: (taskId: string) => Promise<Record<string, string[]>>;
getSourceMaps?: (
url: string
) => Promise<Record<string, Record<string, string[]>>>;
}
export function getProjectGraphDataService() {
if (projectGraphService === undefined) {
if (window.environment === 'dev') {
projectGraphService = new FetchProjectGraphService();
} else if (window.environment === 'watch') {
projectGraphService = new MockProjectGraphService();
} else if (window.environment === 'nx-console') {
projectGraphService = new NxConsoleProjectGraphService();
} else if (window.environment === 'release') {
if (window.localMode === 'build') {
projectGraphService = new LocalProjectGraphService();
} else {
projectGraphService = new FetchProjectGraphService();
}
}
}
return projectGraphService;
}
@@ -0,0 +1,45 @@
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import { ProjectGraphService } from './get-project-graph-data-service';
export class LocalProjectGraphService implements ProjectGraphService {
async getHash(): Promise<string> {
return new Promise((resolve) => resolve('some-hash'));
}
async getProjectGraph(_url: string): Promise<ProjectGraphClientResponse> {
return new Promise((resolve) => resolve(window.projectGraphResponse));
}
async getTaskGraph(_url: string): Promise<TaskGraphClientResponse> {
return new Promise((resolve) => resolve(window.taskGraphResponse));
}
async getExpandedTaskInputs(
taskId: string
): Promise<Record<string, string[]>> {
return new Promise((resolve) =>
resolve(window.expandedTaskInputsResponse[taskId])
);
}
async getSpecificTaskGraph(
_url: string,
projects: string | string[] | null,
targets: string[],
configuration?: string
): Promise<TaskGraphClientResponse> {
// In local mode, we still return the full task graph
// The filtering would happen on the client side if needed
return new Promise((resolve) => resolve(window.taskGraphResponse));
}
async getSourceMaps(
_url: string
): Promise<Record<string, Record<string, string[]>>> {
return new Promise((resolve) => resolve(window.sourceMapsResponse));
}
}
@@ -0,0 +1,160 @@
// nx-ignore-next-line
import type {
ProjectGraphDependency,
ProjectGraphProjectNode,
} from '@nx/devkit';
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import { ProjectGraphService } from './get-project-graph-data-service';
export class MockProjectGraphService implements ProjectGraphService {
private projectGraphsResponse: ProjectGraphClientResponse = {
hash: '79054025255fb1a26e4bc422aef54eb4',
layout: {
appsDir: 'apps',
libsDir: 'libs',
},
projects: [
{
name: 'existing-app-1',
type: 'app',
data: {
root: 'apps/app1',
tags: [],
},
},
{
name: 'existing-lib-1',
type: 'lib',
data: {
root: 'libs/lib1',
tags: [],
},
},
],
dependencies: {
'existing-app-1': [
{
source: 'existing-app-1',
target: 'existing-lib-1',
type: 'static',
},
],
'existing-lib-1': [],
},
fileMap: {
'existing-app-1': [
{
file: 'some/file.ts',
hash: 'ecccd8481d2e5eae0e59928be1bc4c2d071729d7',
deps: ['existing-lib-1'],
},
],
'exiting-lib-1': [],
},
affected: [],
focus: null,
exclude: [],
groupByFolder: false,
isPartial: false,
};
private taskGraphsResponse: TaskGraphClientResponse = {
taskGraph: {
roots: [],
tasks: {},
dependencies: {},
continuousDependencies: {},
},
plans: {},
error: null,
};
constructor(updateFrequency = 5000) {
setInterval(() => this.updateResponse(), updateFrequency);
}
async getHash(): Promise<string> {
return new Promise((resolve) => resolve(this.projectGraphsResponse.hash));
}
getProjectGraph(_url: string): Promise<ProjectGraphClientResponse> {
return new Promise((resolve) => resolve(this.projectGraphsResponse));
}
getTaskGraph(_url: string): Promise<TaskGraphClientResponse> {
return new Promise((resolve) => resolve(this.taskGraphsResponse));
}
getSpecificTaskGraph(
_url: string,
projects: string | string[] | null,
targets: string[],
configuration?: string
): Promise<TaskGraphClientResponse> {
// In mock mode, return the full task graph
return new Promise((resolve) => resolve(this.taskGraphsResponse));
}
getSourceMaps(
_url: string
): Promise<Record<string, Record<string, string[]>>> {
return new Promise((resolve) => resolve({}));
}
async getExpandedTaskInputs(
taskId: string
): Promise<Record<string, string[]>> {
// Generate mock data for the task
const mockInputs: Record<string, string[]> = {
general: ['src/**/*.ts', 'package.json'],
[taskId.split(':')[0]]: [`${taskId.split(':')[0]}/src/**/*.ts`],
external: ['node_modules/**/*'],
};
return new Promise((resolve) => resolve(mockInputs));
}
private createNewProject(): ProjectGraphProjectNode {
const type = Math.random() > 0.25 ? 'lib' : 'app';
const name = `${type}-${this.projectGraphsResponse.projects.length + 1}`;
return {
name,
type,
data: {
root: type === 'app' ? `apps/${name}` : `libs/${name}`,
tags: [],
},
};
}
private updateResponse() {
const newProject = this.createNewProject();
const libProjects = this.projectGraphsResponse.projects.filter(
(project) => project.type === 'lib'
);
const targetDependency =
libProjects[Math.floor(Math.random() * libProjects.length)];
const newDependency: ProjectGraphDependency[] = [
{
source: newProject.name,
target: targetDependency.name,
type: 'static',
},
];
this.projectGraphsResponse = {
...this.projectGraphsResponse,
projects: [...this.projectGraphsResponse.projects, newProject],
dependencies: {
...this.projectGraphsResponse.dependencies,
[newProject.name]: newDependency,
},
};
}
}
@@ -0,0 +1,44 @@
// nx-ignore-next-line
import type {
ProjectGraphClientResponse,
TaskGraphClientResponse,
} from 'nx/src/command-line/graph/graph';
import { ProjectGraphService } from './get-project-graph-data-service';
export class NxConsoleProjectGraphService implements ProjectGraphService {
async getHash(): Promise<string> {
return new Promise((resolve) => resolve('some-hash'));
}
async getProjectGraph(url: string): Promise<ProjectGraphClientResponse> {
return await window.externalApi.loadProjectGraph?.(url);
}
async getTaskGraph(url: string): Promise<TaskGraphClientResponse> {
return await window.externalApi.loadTaskGraph?.(url);
}
async getExpandedTaskInputs(
taskId: string
): Promise<Record<string, string[]>> {
const res = await window.externalApi.loadExpandedTaskInputs?.(taskId);
return res ? res[taskId] : {};
}
async getSpecificTaskGraph(
url: string,
projects: string | string[] | null,
targets: string[],
configuration?: string
): Promise<TaskGraphClientResponse> {
// Use the regular task graph loading through external API
// NxConsole will handle the filtering
return await window.externalApi.loadTaskGraph?.(url);
}
async getSourceMaps(
url: string
): Promise<Record<string, Record<string, string[]>>> {
return await window.externalApi.loadSourceMaps?.(url);
}
}
@@ -0,0 +1,37 @@
// nx-ignore-next-line
import type { ProjectGraphClientResponse } from 'nx/src/command-line/graph/graph';
import { useRef } from 'react';
import { AppConfig } from './app-config';
export function useEnvironmentConfig(): {
exclude: string[];
watch: boolean;
localMode: 'serve' | 'build';
projectGraphResponse?: ProjectGraphClientResponse;
environment: 'dev' | 'watch' | 'release' | 'nx-console' | 'docs';
appConfig: AppConfig;
useXstateInspect: boolean;
} {
const environmentConfig = useRef(getEnvironmentConfig());
return environmentConfig.current;
}
export function getEnvironmentConfig() {
return {
exclude: window.exclude,
watch: window.watch,
localMode: window.localMode,
projectGraphResponse: window.projectGraphResponse,
// If this was not built into JS or HTML, then it is rendered on docs (nx.dev).
environment: window.environment ?? ('docs' as const),
appConfig: {
...window.appConfig,
showExperimentalFeatures:
localStorage.getItem('showExperimentalFeatures') === 'true'
? true
: window.appConfig?.showExperimentalFeatures,
},
useXstateInspect: window.useXstateInspect,
};
}
+37
View File
@@ -0,0 +1,37 @@
import { useEffect, useRef } from 'react';
export const usePoll = (
callback: () => Promise<void>,
delay: number,
condition: boolean
) => {
const savedCallback = useRef(() => Promise.resolve());
useEffect(() => {
if (condition) {
savedCallback.current = callback;
}
}, [callback, condition]);
useEffect(() => {
if (!condition) {
return;
}
let timeoutId: NodeJS.Timeout;
async function callTickAfterDelay() {
await savedCallback.current();
if (delay !== null) {
timeoutId = setTimeout(callTickAfterDelay, delay);
}
}
callTickAfterDelay();
return () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}, [delay, condition]);
};
@@ -0,0 +1,65 @@
import { To, useParams, useSearchParams } from 'react-router-dom';
import { getEnvironmentConfig } from './use-environment-config';
export const useRouteConstructor = (): ((
to: To,
retainSearchParams:
| boolean
| ((searchParams: URLSearchParams) => URLSearchParams),
searchParamsKeysToOmit?: string[]
) => To) => {
const { environment } = getEnvironmentConfig();
const { selectedWorkspaceId } = useParams();
const [searchParams] = useSearchParams();
return (
to: To,
retainSearchParams = true,
searchParamsKeysToOmit: string[] = []
) => {
if (searchParamsKeysToOmit?.length) {
searchParamsKeysToOmit.forEach((key) => {
searchParams.delete(key);
});
}
let pathname: string | undefined = '';
if (typeof to === 'object') {
if (environment === 'dev') {
pathname = `/${selectedWorkspaceId}${to.pathname}`;
} else {
pathname = to.pathname;
}
return {
...to,
pathname,
search: to.search
? to.search.toString()
: getSearchParams(retainSearchParams, searchParams),
};
} else {
if (environment === 'dev') {
pathname = `/${selectedWorkspaceId}${to}`;
} else {
pathname = to;
}
return {
pathname,
search: getSearchParams(retainSearchParams, searchParams),
};
}
};
};
function getSearchParams(
retainSearchParams:
| boolean
| ((searchParams: URLSearchParams) => URLSearchParams),
searchParams: URLSearchParams
) {
return typeof retainSearchParams === 'function'
? retainSearchParams(searchParams).toString()
: retainSearchParams
? searchParams.toString()
: '';
}
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx"
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"outDir": "dist",
"types": ["node"],
"lib": ["ES2022", "DOM"]
},
"files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"jest.config.ts"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"],
"references": []
}