@likec4/core
Advanced tools
Comparing version 0.36.0 to 0.37.0
import type { ModelIndex } from '../model-index'; | ||
import type { Fqn, Element, Relation } from '../types'; | ||
import type { Fqn, Element, Relation, ViewRuleExpression, ElementView } from '../types'; | ||
export type ComputeCtxPatch = { | ||
@@ -17,2 +17,4 @@ elements?: Element[]; | ||
exclude({ elements, relations, implicits }: ComputeCtxPatch): ComputeCtx; | ||
processViewRules(viewRules: ViewRuleExpression[]): ComputeCtx; | ||
static create(view: ElementView, index: ModelIndex): ComputeCtx; | ||
} |
import { difference } from "rambdax"; | ||
import { Expr, isStrictElementView, isViewRuleExpression } from "../types/index.js"; | ||
import { | ||
excludeElementKindOrTag, | ||
excludeElementRef, | ||
excludeInOutExpr, | ||
excludeIncomingExpr, | ||
excludeOutgoingExpr, | ||
excludeRelationExpr, | ||
excludeWildcardRef, | ||
includeElementKindOrTag, | ||
includeElementRef, | ||
includeInOutExpr, | ||
includeIncomingExpr, | ||
includeOutgoingExpr, | ||
includeRelationExpr, | ||
includeWildcardRef | ||
} from "./compute-predicates.js"; | ||
import { nonexhaustive } from "../errors/index.js"; | ||
export class ComputeCtx { | ||
@@ -10,7 +28,3 @@ constructor(index, root, elements = /* @__PURE__ */ new Set(), relations = /* @__PURE__ */ new Set(), implicits = /* @__PURE__ */ new Set()) { | ||
} | ||
include({ | ||
elements, | ||
relations, | ||
implicits | ||
}) { | ||
include({ elements, relations, implicits }) { | ||
return new ComputeCtx( | ||
@@ -24,12 +38,6 @@ this.index, | ||
} | ||
exclude({ | ||
elements, | ||
relations, | ||
implicits | ||
}) { | ||
exclude({ elements, relations, implicits }) { | ||
let newImplicits = implicits ? new Set(difference([...this.implicits], implicits)) : this.implicits; | ||
if (elements) { | ||
newImplicits = new Set( | ||
difference([...newImplicits], elements) | ||
); | ||
newImplicits = new Set(difference([...newImplicits], elements)); | ||
} | ||
@@ -44,2 +52,50 @@ return new ComputeCtx( | ||
} | ||
processViewRules(viewRules) { | ||
let ctx = this; | ||
for (const { isInclude, exprs } of viewRules) { | ||
for (const expr of exprs) { | ||
if (Expr.isElementKindExpr(expr) || Expr.isElementTagExpr(expr)) { | ||
ctx = isInclude ? includeElementKindOrTag(ctx, expr) : excludeElementKindOrTag(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isElementRef(expr)) { | ||
ctx = isInclude ? includeElementRef(ctx, expr) : excludeElementRef(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isWildcard(expr)) { | ||
ctx = isInclude ? includeWildcardRef(ctx, expr) : excludeWildcardRef(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isIncoming(expr)) { | ||
ctx = isInclude ? includeIncomingExpr(ctx, expr) : excludeIncomingExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isOutgoing(expr)) { | ||
ctx = isInclude ? includeOutgoingExpr(ctx, expr) : excludeOutgoingExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isInOut(expr)) { | ||
ctx = isInclude ? includeInOutExpr(ctx, expr) : excludeInOutExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isRelation(expr)) { | ||
ctx = isInclude ? includeRelationExpr(ctx, expr) : excludeRelationExpr(ctx, expr); | ||
continue; | ||
} | ||
nonexhaustive(expr); | ||
} | ||
} | ||
return ctx; | ||
} | ||
static create(view, index) { | ||
const rootElement = isStrictElementView(view) ? view.viewOf : null; | ||
let ctx = new ComputeCtx(index, rootElement); | ||
const rulesInclude = view.rules.filter(isViewRuleExpression); | ||
if (rootElement && rulesInclude.length == 0) { | ||
ctx = ctx.include({ | ||
elements: [index.find(rootElement)] | ||
}); | ||
} | ||
return ctx.processViewRules(rulesInclude); | ||
} | ||
} |
import type { ModelIndex } from '../model-index'; | ||
import { type ElementView, type ComputedView } from '../types'; | ||
import { type ComputedView, type ElementView } from '../types'; | ||
export declare function computeElementView(view: ElementView, index: ModelIndex): ComputedView; |
import { allPass, find } from "remeda"; | ||
import { nonNullable, nonexhaustive } from "../errors/index.js"; | ||
import { nonNullable } from "../errors/index.js"; | ||
import { | ||
DefaultElementShape, | ||
DefaultThemeColor, | ||
Expr, | ||
isViewRuleAutoLayout, | ||
isViewRuleExpression, | ||
isViewRuleStyle | ||
@@ -14,18 +12,2 @@ } from "../types/index.js"; | ||
import { ComputeCtx } from "./compute-ctx.js"; | ||
import { | ||
excludeElementKindOrTag, | ||
excludeElementRef, | ||
excludeInOutExpr, | ||
excludeIncomingExpr, | ||
excludeOutgoingExpr, | ||
excludeRelationExpr, | ||
excludeWildcardRef, | ||
includeElementKindOrTag, | ||
includeElementRef, | ||
includeInOutExpr, | ||
includeIncomingExpr, | ||
includeOutgoingExpr, | ||
includeRelationExpr, | ||
includeWildcardRef | ||
} from "./compute-predicates.js"; | ||
import { applyViewRuleStyles } from "./utils/applyViewRuleStyles.js"; | ||
@@ -61,43 +43,3 @@ import { sortNodes } from "./utils/sortNodes.js"; | ||
export function computeElementView(view, index) { | ||
const rootElement = view.viewOf ?? null; | ||
let ctx = new ComputeCtx(index, rootElement); | ||
const rulesInclude = view.rules.filter(isViewRuleExpression); | ||
if (rootElement && rulesInclude.length == 0) { | ||
ctx = ctx.include({ | ||
elements: [index.find(rootElement)] | ||
}); | ||
} | ||
for (const { isInclude, exprs } of rulesInclude) { | ||
for (const expr of exprs) { | ||
if (Expr.isElementKindExpr(expr) || Expr.isElementTagExpr(expr)) { | ||
ctx = isInclude ? includeElementKindOrTag(ctx, expr) : excludeElementKindOrTag(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isElementRef(expr)) { | ||
ctx = isInclude ? includeElementRef(ctx, expr) : excludeElementRef(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isWildcard(expr)) { | ||
ctx = isInclude ? includeWildcardRef(ctx, expr) : excludeWildcardRef(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isIncoming(expr)) { | ||
ctx = isInclude ? includeIncomingExpr(ctx, expr) : excludeIncomingExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isOutgoing(expr)) { | ||
ctx = isInclude ? includeOutgoingExpr(ctx, expr) : excludeOutgoingExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isInOut(expr)) { | ||
ctx = isInclude ? includeInOutExpr(ctx, expr) : excludeInOutExpr(ctx, expr); | ||
continue; | ||
} | ||
if (Expr.isRelation(expr)) { | ||
ctx = isInclude ? includeRelationExpr(ctx, expr) : excludeRelationExpr(ctx, expr); | ||
continue; | ||
} | ||
nonexhaustive(expr); | ||
} | ||
} | ||
const ctx = ComputeCtx.create(view, index); | ||
const allElements = [...ctx.elements, ...ctx.implicits].sort(compareByFqnHierarchically).reverse(); | ||
@@ -113,6 +55,3 @@ const elementsWithRelations = /* @__PURE__ */ new Set(); | ||
} | ||
const target = find( | ||
allElements, | ||
allPass([anscestorOf(rel.target), (e) => !isSameHierarchy(e, source)]) | ||
); | ||
const target = find(allElements, allPass([anscestorOf(rel.target), (e) => !isSameHierarchy(e, source)])); | ||
if (!target) { | ||
@@ -119,0 +58,0 @@ continue; |
@@ -1,4 +0,4 @@ | ||
import { ModelIndex } from '../model-index'; | ||
import type { ComputedView, Element, ElementView, Fqn, Relation, RelationID, ViewID } from '../types'; | ||
import { type BaseError } from '..'; | ||
import type { BaseError } from '../errors'; | ||
import type { ModelIndex } from '../model-index'; | ||
import { type ComputedView, type ElementView } from '../types'; | ||
type ComputeViewResult = { | ||
@@ -13,14 +13,3 @@ isSuccess: true; | ||
export declare function computeView(view: ElementView, index: ModelIndex): ComputeViewResult; | ||
export type CmpInputModel = { | ||
elements: Record<Fqn, Element>; | ||
relations: Record<RelationID, Relation>; | ||
views: ElementView[]; | ||
}; | ||
export type CmpOutputModel = { | ||
elements: Record<Fqn, Element>; | ||
relations: Record<RelationID, Relation>; | ||
views: Record<ViewID, ComputedView>; | ||
}; | ||
export declare function computeViews(model: CmpInputModel): CmpOutputModel; | ||
export declare function assignNavigateTo<R extends Iterable<ComputedView>>(views: R): R; | ||
export {}; |
@@ -1,5 +0,4 @@ | ||
import { compact, find, map, mapToObj } from "remeda"; | ||
import { ModelIndex } from "../model-index/index.js"; | ||
import { find } from "rambdax"; | ||
import { normalizeError } from "../errors/index.js"; | ||
import { computeElementView } from "./compute-element-view.js"; | ||
import { normalizeError } from "../index.js"; | ||
export function computeView(view, index) { | ||
@@ -19,18 +18,9 @@ try { | ||
} | ||
export function computeViews(model) { | ||
const index = ModelIndex.from(model); | ||
const computedViews = compact(map(model.views, (view) => computeView(view, index).view)); | ||
return { | ||
elements: model.elements, | ||
relations: model.relations, | ||
views: mapToObj(computedViews, (view) => [view.id, view]) | ||
}; | ||
} | ||
export function assignNavigateTo(views) { | ||
const allElementViews = /* @__PURE__ */ new Map(); | ||
for (const { id, viewOf } of views) { | ||
if (viewOf) { | ||
const viewsOf = allElementViews.get(viewOf) ?? []; | ||
viewsOf.push(id); | ||
allElementViews.set(viewOf, viewsOf); | ||
for (const v of views) { | ||
if (v.viewOf && !v.extends) { | ||
const viewsOf = allElementViews.get(v.viewOf) ?? []; | ||
viewsOf.push(v.id); | ||
allElementViews.set(v.viewOf, viewsOf); | ||
} | ||
@@ -40,3 +30,3 @@ } | ||
for (const node of nodes) { | ||
const navigateTo = find(allElementViews.get(node.id) ?? [], (v) => v !== id); | ||
const navigateTo = find((v) => v !== id, allElementViews.get(node.id) ?? []); | ||
if (navigateTo) { | ||
@@ -43,0 +33,0 @@ node.navigateTo = navigateTo; |
export * from './compute'; | ||
export * from './resolve-extended-views'; | ||
export * from './EdgeBuilder'; |
export * from "./compute.js"; | ||
export * from "./resolve-extended-views.js"; | ||
export * from "./EdgeBuilder.js"; |
@@ -6,2 +6,2 @@ import type { BaseErrorOptions } from './_base'; | ||
} | ||
export declare function nonNullable<T>(value: T): NonNullable<T>; | ||
export declare function nonNullable<T>(value: T, message?: string): T & {}; |
@@ -8,7 +8,7 @@ import { BaseError } from "./_base.js"; | ||
} | ||
export function nonNullable(value) { | ||
export function nonNullable(value, message) { | ||
if (typeof value === "undefined" || value == null) { | ||
throw new NullableError(`Expected defined value, but received ${value}`); | ||
throw new NullableError(message ?? `Expected defined value, but received ${value}`); | ||
} | ||
return value; | ||
} |
import type { Opaque } from './opaque'; | ||
import type { ElementKind, ElementShape, Fqn, Tag } from './element'; | ||
import type { RelationID } from './relation'; | ||
import type { ElementView, ViewID, ViewRuleAutoLayout } from './view'; | ||
import type { BasicElementView, ViewID, ViewRuleAutoLayout } from './view'; | ||
import type { IconUrl, NonEmptyArray } from './_common'; | ||
@@ -34,3 +34,5 @@ import type { ThemeColor } from './theme'; | ||
} | ||
export interface ComputedView extends ElementView { | ||
export interface ComputedView extends BasicElementView { | ||
viewOf?: Fqn; | ||
extends?: ViewID; | ||
autoLayout: ViewRuleAutoLayout['autoLayout']; | ||
@@ -37,0 +39,0 @@ nodes: ComputedNode[]; |
@@ -1,5 +0,10 @@ | ||
import type { Fqn, Element } from './element'; | ||
import type { RelationID, Relation } from './relation'; | ||
import type { ViewID } from './view'; | ||
import type { ComputedView } from './computed-view'; | ||
import type { Element, Fqn } from './element'; | ||
import type { Relation, RelationID } from './relation'; | ||
import type { ElementView, ViewID } from './view'; | ||
export interface LikeC4RawModel { | ||
elements: Record<Fqn, Element>; | ||
relations: Record<RelationID, Relation>; | ||
views: Record<ViewID, ElementView>; | ||
} | ||
export interface LikeC4Model { | ||
@@ -6,0 +11,0 @@ elements: Record<Fqn, Element>; |
@@ -26,3 +26,3 @@ import type { Opaque } from './opaque'; | ||
export type ViewRule = ViewRuleExpression | ViewRuleStyle | ViewRuleAutoLayout; | ||
export interface ElementView { | ||
export interface BasicElementView { | ||
readonly id: ViewID; | ||
@@ -36,1 +36,10 @@ readonly viewOf?: Fqn; | ||
} | ||
export interface StrictElementView extends BasicElementView { | ||
readonly viewOf: Fqn; | ||
} | ||
export declare function isStrictElementView(view: ElementView): view is StrictElementView; | ||
export interface ExtendsElementView extends BasicElementView { | ||
readonly extends: ViewID; | ||
} | ||
export declare function isExtendsElementView(view: ElementView): view is ExtendsElementView; | ||
export type ElementView = StrictElementView | ExtendsElementView | BasicElementView; |
@@ -10,1 +10,7 @@ export function isViewRuleExpression(rule) { | ||
} | ||
export function isStrictElementView(view) { | ||
return "viewOf" in view; | ||
} | ||
export function isExtendsElementView(view) { | ||
return "extends" in view; | ||
} |
@@ -1,2 +0,1 @@ | ||
import { anyPass } from "remeda"; | ||
import { compareFqnHierarchically, isAncestor } from "./fqn.js"; | ||
@@ -21,3 +20,3 @@ import { either } from "rambdax"; | ||
const isAnyBetween = (source, target) => { | ||
return anyPass([isBetween(source, target), isBetween(target, source)]); | ||
return either(isBetween(source, target), isBetween(target, source)); | ||
}; | ||
@@ -24,0 +23,0 @@ const isIncoming = (target) => { |
{ | ||
"name": "@likec4/core", | ||
"version": "0.36.0", | ||
"version": "0.37.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "homepage": "https://likec4.dev", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
128634
110
3824