style(arch): linting

This commit is contained in:
NicolasNewman 2024-05-06 10:04:17 -05:00
parent 734bde3877
commit 48e6901936
12 changed files with 142 additions and 97 deletions

View File

@ -25,7 +25,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'sankey',
'block',
'packet',
'architecture'
'architecture',
] as const;
/**

View File

@ -40,17 +40,25 @@ const state = new ImperativeState<ArchitectureState>(() => ({
registeredIds: {},
config: DEFAULT_ARCHITECTURE_CONFIG,
dataStructures: undefined,
elements: {}
}))
elements: {},
}));
const clear = (): void => {
state.reset()
state.reset();
commonClear();
};
const addService = function ({ id, icon, in: parent, title, iconText }: Omit<ArchitectureService, "edges">) {
const addService = function ({
id,
icon,
in: parent,
title,
iconText,
}: Omit<ArchitectureService, 'edges'>) {
if (state.records.registeredIds[id] !== undefined) {
throw new Error(`The service id [${id}] is already in use by another ${state.records.registeredIds[id]}`);
throw new Error(
`The service id [${id}] is already in use by another ${state.records.registeredIds[id]}`
);
}
if (parent !== undefined) {
if (id === parent) {
@ -82,7 +90,9 @@ const getServices = (): ArchitectureService[] => Object.values(state.records.ser
const addGroup = function ({ id, icon, in: parent, title }: ArchitectureGroup) {
if (state.records.registeredIds[id] !== undefined) {
throw new Error(`The group id [${id}] is already in use by another ${state.records.registeredIds[id]}`);
throw new Error(
`The group id [${id}] is already in use by another ${state.records.registeredIds[id]}`
);
}
if (parent !== undefined) {
if (id === parent) {
@ -111,10 +121,15 @@ const getGroups = (): ArchitectureGroup[] => {
return Object.values(state.records.groups);
};
const addEdge = function (
{ lhsId, rhsId, lhsDir, rhsDir, lhsInto, rhsInto, title }: ArchitectureEdge
) {
const addEdge = function ({
lhsId,
rhsId,
lhsDir,
rhsDir,
lhsInto,
rhsInto,
title,
}: ArchitectureEdge) {
if (!isArchitectureDirection(lhsDir)) {
throw new Error(
`Invalid direction given for left hand side of edge ${lhsId}--${rhsId}. Expected (L,R,T,B) got ${lhsDir}`
@ -152,7 +167,6 @@ const addEdge = function (
state.records.services[lhsId].edges.push(state.records.edges[state.records.edges.length - 1]);
state.records.services[rhsId].edges.push(state.records.edges[state.records.edges.length - 1]);
} else if (state.records.groups[lhsId] && state.records.groups[rhsId]) {
}
};
@ -168,28 +182,27 @@ const getDataStructures = () => {
// Create an adjacency list of the diagram to perform BFS on
// Outer reduce applied on all services
// Inner reduce applied on the edges for a service
const adjList = Object.entries(state.records.services).reduce<{ [id: string]: ArchitectureDirectionPairMap }>(
(prevOuter, [id, service]) => {
prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
if (edge.lhsId === id) {
// source is LHS
const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
if (pair) {
prevInner[pair] = edge.rhsId;
}
} else {
// source is RHS
const pair = getArchitectureDirectionPair(edge.rhsDir, edge.lhsDir);
if (pair) {
prevInner[pair] = edge.lhsId;
}
const adjList = Object.entries(state.records.services).reduce<{
[id: string]: ArchitectureDirectionPairMap;
}>((prevOuter, [id, service]) => {
prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
if (edge.lhsId === id) {
// source is LHS
const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
if (pair) {
prevInner[pair] = edge.rhsId;
}
return prevInner;
}, {});
return prevOuter;
},
{}
);
} else {
// source is RHS
const pair = getArchitectureDirectionPair(edge.rhsDir, edge.lhsDir);
if (pair) {
prevInner[pair] = edge.lhsId;
}
}
return prevInner;
}, {});
return prevOuter;
}, {});
// Configuration for the initial pass of BFS
const firstId = Object.keys(adjList)[0];

View File

@ -12,7 +12,7 @@ import type {
ArchitectureDataStructures,
ArchitectureSpatialMap,
EdgeSingularData,
EdgeSingular
EdgeSingular,
} from './architectureTypes.js';
import {
type ArchitectureDB,
@ -25,7 +25,7 @@ import {
isArchitectureDirectionXY,
isArchitectureDirectionY,
nodeData,
edgeData
edgeData,
} from './architectureTypes.js';
import { select } from 'd3';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
@ -54,8 +54,10 @@ function addServices(services: ArchitectureService[], cy: cytoscape.Core) {
function positionServices(db: ArchitectureDB, cy: cytoscape.Core) {
cy.nodes().map((node) => {
const data = nodeData(node)
if (data.type === 'group') { return; }
const data = nodeData(node);
if (data.type === 'group') {
return;
}
data.x = node.position().x;
data.y = node.position().y;
@ -126,8 +128,12 @@ function getAlignments(spatialMaps: ArchitectureSpatialMap[]): fcose.FcoseAlignm
const verticalAlignments: Record<number, string[]> = {};
// Group service ids in an object with their x and y coordinate as the key
Object.entries(spatialMap).forEach(([id, [x, y]]) => {
if (!horizontalAlignments[y]) { horizontalAlignments[y] = []; }
if (!verticalAlignments[x]) { verticalAlignments[x] = []; }
if (!horizontalAlignments[y]) {
horizontalAlignments[y] = [];
}
if (!verticalAlignments[x]) {
verticalAlignments[x] = [];
}
horizontalAlignments[y].push(id);
verticalAlignments[x].push(id);
});
@ -221,7 +227,7 @@ function layoutArchitecture(
selector: 'edge',
style: {
'curve-style': 'straight',
'label': 'data(label)',
label: 'data(label)',
'source-endpoint': 'data(sourceEndpoint)',
'target-endpoint': 'data(targetEndpoint)',
},
@ -300,16 +306,16 @@ function layoutArchitecture(
// Hacky fix for: https://github.com/iVis-at-Bilkent/cytoscape.js-fcose/issues/67
idealEdgeLength(edge: EdgeSingular) {
const [nodeA, nodeB] = edge.connectedNodes();
const { parent: parentA } = nodeData(nodeA)
const { parent: parentB } = nodeData(nodeB)
const { parent: parentA } = nodeData(nodeA);
const { parent: parentB } = nodeData(nodeB);
const elasticity =
parentA === parentB ? 1.5 * getConfigField('iconSize') : 0.5 * getConfigField('iconSize');
return elasticity;
},
edgeElasticity(edge: EdgeSingular) {
const [nodeA, nodeB] = edge.connectedNodes();
const { parent: parentA } = nodeData(nodeA)
const { parent: parentB } = nodeData(nodeB)
const { parent: parentA } = nodeData(nodeA);
const { parent: parentB } = nodeData(nodeB);
const elasticity = parentA === parentB ? 0.45 : 0.001;
return elasticity;
},
@ -374,7 +380,7 @@ function layoutArchitecture(
if (sX !== tX && sY !== tY) {
const sEP = edge.sourceEndpoint();
const tEP = edge.targetEndpoint();
const { sourceDir } = edgeData(edge)
const { sourceDir } = edgeData(edge);
const [pointX, pointY] = isArchitectureDirectionY(sourceDir)
? [sEP.x, tEP.y]
: [tEP.x, sEP.y];

View File

@ -21,8 +21,7 @@ export type ArchitectureDirectionPair = Exclude<
>;
export type ArchitectureDirectionPairXY = Exclude<
InvalidArchitectureDirectionPair,
'LL' | 'RR' | 'TT' | 'BB'
| 'LR' | 'RL' | 'TB' | 'BT'
'LL' | 'RR' | 'TT' | 'BB' | 'LR' | 'RL' | 'TB' | 'BT'
>;
export const ArchitectureDirectionName = {
@ -85,7 +84,7 @@ export const isArchitectureDirectionXY = function (
};
export const isArchitecturePairXY = function (
pair: ArchitectureDirectionPair,
pair: ArchitectureDirectionPair
): pair is ArchitectureDirectionPairXY {
const lhs = pair[0] as ArchitectureDirection;
const rhs = pair[1] as ArchitectureDirection;
@ -161,13 +160,13 @@ export const getArchitectureDirectionXYFactors = function (
pair: ArchitectureDirectionPairXY
): number[] {
if (pair === 'LT' || pair === 'TL') {
return [1, 1]
return [1, 1];
} else if (pair === 'BL' || pair === 'LB') {
return [1, -1]
return [1, -1];
} else if (pair === 'BR' || pair === 'RB') {
return [-1, -1]
return [-1, -1];
} else {
return [-1, 1]
return [-1, 1];
}
};
@ -209,13 +208,11 @@ export interface ArchitectureEdge {
export interface ArchitectureDB extends DiagramDB {
clear: () => void;
addService: (service: Omit<ArchitectureService, "edges">) => void;
addService: (service: Omit<ArchitectureService, 'edges'>) => void;
getServices: () => ArchitectureService[];
addGroup: (group: ArchitectureGroup) => void;
getGroups: () => ArchitectureGroup[];
addEdge: (
edge: ArchitectureEdge
) => void;
addEdge: (edge: ArchitectureEdge) => void;
getEdges: () => ArchitectureEdge[];
setElementForId: (id: string, element: D3Element) => void;
getElementById: (id: string) => D3Element;
@ -257,7 +254,7 @@ export type EdgeSingularData = {
export const edgeData = (edge: cytoscape.EdgeSingular) => {
return edge.data() as EdgeSingularData;
}
};
export interface EdgeSingular extends cytoscape.EdgeSingular {
_private: {
@ -275,28 +272,29 @@ export interface EdgeSingular extends cytoscape.EdgeSingular {
data<T extends keyof EdgeSingularData>(key: T): EdgeSingularData[T];
}
export type NodeSingularData = {
type: 'service';
id: string;
icon?: string;
label?: string;
parent?: string;
width: number;
height: number;
[key: string]: any;
}
export type NodeSingularData =
| {
type: 'group';
id: string;
icon?: string;
label?: string;
parent?: string;
[key: string]: any;
};
type: 'service';
id: string;
icon?: string;
label?: string;
parent?: string;
width: number;
height: number;
[key: string]: any;
}
| {
type: 'group';
id: string;
icon?: string;
label?: string;
parent?: string;
[key: string]: any;
};
export const nodeData = (node: cytoscape.NodeSingular) => {
return node.data() as NodeSingularData;
}
};
export interface NodeSingular extends cytoscape.NodeSingular {
_private: {

View File

@ -227,7 +227,7 @@ export const drawServices = function (
},
getConfig()
);
textElem
.attr('dy', '1em')
.attr('alignment-baseline', 'middle')
@ -247,14 +247,24 @@ export const drawServices = function (
} else if (service.iconText) {
bkgElem = getIcon('blank')?.(bkgElem, iconSize);
const textElemContainer = bkgElem.append('g');
const fo = textElemContainer.append('foreignObject').attr('width', iconSize).attr('height', iconSize);
const fo = textElemContainer
.append('foreignObject')
.attr('width', iconSize)
.attr('height', iconSize);
const divElem = fo
.append('div')
.attr('class', 'node-icon-text')
.attr('style', `height: ${iconSize}px;`)
.append('div').html(service.iconText);
const fontSize = parseInt(window.getComputedStyle(divElem.node(), null).getPropertyValue("font-size").replace(/[^\d]/g, '')) ?? 16;
divElem.attr('style', `-webkit-line-clamp: ${Math.floor((iconSize - 2) / fontSize)};`)
.append('div')
.html(service.iconText);
const fontSize =
parseInt(
window
.getComputedStyle(divElem.node(), null)
.getPropertyValue('font-size')
.replace(/[^\d]/g, '')
) ?? 16;
divElem.attr('style', `-webkit-line-clamp: ${Math.floor((iconSize - 2) / fontSize)};`);
} else {
bkgElem
.append('path')

View File

@ -20,7 +20,7 @@ architecture
## Syntax
The building blocks of an architecture are `groups`, `services`, and `edges`.
The building blocks of an architecture are `groups`, `services`, and `edges`.
For supporting components, icons are declared by surrounding the icon name with `()`, while labels are declared by surrounding the text with `[]`.
@ -29,6 +29,7 @@ To begin an architecture diagram, use the keyword `architecture`, followed by yo
### Groups
The syntax for declaring a group is:
```
group {group id}({icon name})[{title}] (in {parent id})?
```
@ -48,12 +49,15 @@ group private_api(cloud)[Private API] in public_api
```
### Services
The syntax for declaring a group is:
```
service {service id}({icon name})[{title}] (in {parent id})?
```
Put together:
```
service database(db)[Database]
```
@ -67,6 +71,7 @@ service database(db)[Database] in private_api
```
### Edges
TODO
## Configuration
## Configuration

View File

@ -16,7 +16,7 @@ import type { DetailedError } from './utils.js';
import type { ExternalDiagramDefinition } from './diagram-api/types.js';
import type { UnknownDiagramError } from './errors.js';
import type { IconLibrary, IconResolver } from './rendering-util/svgRegister.js';
import { createIcon } from './rendering-util/svgRegister.js';
import { createIcon } from './rendering-util/svgRegister.js';
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
export type {
@ -29,10 +29,10 @@ export type {
ParseResult,
UnknownDiagramError,
IconLibrary,
IconResolver
IconResolver,
};
export { createIcon }
export { createIcon };
export interface RunOptions {
/**

View File

@ -5,9 +5,9 @@
import { createIcon } from '../svgRegister.js';
export default createIcon(
`<g>
`<g>
<rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>
<path d="m65,47.5c0,2.76-2.24,5-5,5H20c-2.76,0-5-2.24-5-5,0-1.87,1.03-3.51,2.56-4.36-.04-.21-.06-.42-.06-.64,0-2.6,2.48-4.74,5.65-4.97,1.65-4.51,6.34-7.76,11.85-7.76.86,0,1.69.08,2.5.23,2.09-1.57,4.69-2.5,7.5-2.5,6.1,0,11.19,4.38,12.28,10.17,2.14.56,3.72,2.51,3.72,4.83,0,.03,0,.07-.01.1,2.29.46,4.01,2.48,4.01,4.9Z" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>
</g>`,
80
);
80
);

View File

@ -43,4 +43,12 @@ const getIcon = (name: string): IconResolver | null => {
return icons['unknown'];
};
export { registerIcon, registerIcons, getIcon, isIconNameInUse, createIcon, IconLibrary, IconResolver };
export {
registerIcon,
registerIcons,
getIcon,
isIconNameInUse,
createIcon,
IconLibrary,
IconResolver,
};

View File

@ -35,7 +35,10 @@ export type ArchitectureServices = LangiumCoreServices & ArchitectureAddedServic
* Dependency injection module that overrides Langium default services and
* contributes the declared `Architecture` services.
*/
export const ArchitectureModule: Module<ArchitectureServices, PartialLangiumCoreServices & ArchitectureAddedServices> = {
export const ArchitectureModule: Module<
ArchitectureServices,
PartialLangiumCoreServices & ArchitectureAddedServices
> = {
parser: {
TokenBuilder: () => new ArchitectureTokenBuilder(),
ValueConverter: () => new ArchitectureValueConverter(),
@ -56,7 +59,9 @@ export const ArchitectureModule: Module<ArchitectureServices, PartialLangiumCore
* @param context - Optional module context with the LSP connection
* @returns An object wrapping the shared services and the language-specific services
*/
export function createArchitectureServices(context: DefaultSharedCoreModuleContext = EmptyFileSystem): {
export function createArchitectureServices(
context: DefaultSharedCoreModuleContext = EmptyFileSystem
): {
shared: LangiumSharedCoreServices;
Architecture: ArchitectureServices;
} {

View File

@ -10,12 +10,12 @@ export class ArchitectureValueConverter extends AbstractMermaidValueConverter {
_cstNode: CstNode
): ValueType | undefined {
if (rule.name === 'ARCH_ICON') {
return input.replace(/[()]/g, '').trim();
return input.replace(/[()]/g, '').trim();
} else if (rule.name === 'ARCH_TEXT_ICON') {
return input.replace(/[()"]/g, '');
return input.replace(/[()"]/g, '');
} else if (rule.name === 'ARCH_TITLE') {
return input.replace(/[[\]]/g, '').trim();
return input.replace(/[[\]]/g, '').trim();
}
return undefined
return undefined;
}
}

View File

@ -12,7 +12,7 @@ export {
isPacketBlock,
isPie,
isPieSection,
isArchitecture
isArchitecture,
} from './generated/ast.js';
export {
@ -20,7 +20,7 @@ export {
MermaidGeneratedSharedModule,
PacketGeneratedModule,
PieGeneratedModule,
ArchitectureGeneratedModule
ArchitectureGeneratedModule,
} from './generated/module.js';
export * from './common/index.js';