Skip to content

Commit

Permalink
feat: custom style engine and @style rule in sequenceDiagram
Browse files Browse the repository at this point in the history
  • Loading branch information
hikerpig committed Aug 29, 2021
1 parent f30cbd9 commit 1bf902c
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 18 deletions.
10 changes: 8 additions & 2 deletions packages/pintora-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { logger, setLogLevel } from './logger'
import configApi from './config'

export * from './util'
import { encodeForUrl, decodeCodeInUrl, makeMark, calculateTextDimensions } from './util'
import { encodeForUrl, decodeCodeInUrl, makeMark, calculateTextDimensions, parseColor } from './util'
import { symbolRegistry, SymbolDef, SymbolStyleAttrs } from './symbol-registry'
import { StyleParam, interpreteStyles } from './style-engine'
import * as styleEngine from './style-engine'

export {
logger,
Expand All @@ -15,6 +17,8 @@ export {
symbolRegistry,
SymbolDef,
SymbolStyleAttrs,
StyleParam,
interpreteStyles,
}

type DrawOptions = {
Expand All @@ -24,6 +28,8 @@ type DrawOptions = {
const pintora = {
configApi,
diagramRegistry,
symbolRegistry,
styleEngine,
parseAndDraw(text: string, opts: DrawOptions) {
const { onError } = opts
const diagram = diagramRegistry.detectDiagram(text)
Expand All @@ -48,8 +54,8 @@ const pintora = {
decodeCodeInUrl,
makeMark,
calculateTextDimensions,
parseColor,
},
symbolRegistry,
}

export default pintora
62 changes: 62 additions & 0 deletions packages/pintora-core/src/style-engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* This module evaluate custom style params to real style configs
*/
import { parseColor } from './util/color'

export type StyleValueType = 'color' | 'fontSize'

export type StyleMeta = {
valueType: StyleValueType | StyleValueType[]
}

export type StyleParam<K = string> = {
key: K
value: string
}

type StyleEvaluateResult<T> = { valid: true; value: T } | { valid: false }

interface StyleValueTypeMap {
color: string
fontSize: number
}

const styleValueEvaluators: { [K in StyleValueType]: (p: StyleParam) => StyleEvaluateResult<StyleValueTypeMap[K]> } = {
color({ value }) {
const parsed = parseColor(value)
return { value: parsed.color, valid: true }
},
fontSize({ value }) {
const parsed = parseInt(value)
if (isNaN(parsed)) return { valid: false }
return { value: parsed, valid: true }
},
}

type StyleRuleMap = Record<string, StyleMeta>

/**
* Generate style config from style params
*/
export function interpreteStyles<T extends StyleRuleMap>(
ruleMap: T,
params: StyleParam[],
): { [K in keyof T]: T[K]['valueType'] } {
const out: any = {}
params.forEach(param => {
const meta = ruleMap[param.key]
if (!meta) return
const valueTypes = Array.isArray(meta.valueType) ? meta.valueType : [meta.valueType]
for (const valueType of valueTypes) {
const evaluator = styleValueEvaluators[valueType]
if (!evaluator) continue
const result = evaluator(param)
if (result.valid) {
out[param.key] = result.value
return
}
}
})
// console.log('interpreteStyles', out)
return out
}
File renamed without changes.
1 change: 1 addition & 0 deletions packages/pintora-core/src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './geometry'
export { IFont, calculateTextDimensions } from './text-metric'
export { encodeForUrl, decodeCodeInUrl } from './encode'
export { makeMark } from './mark'
export { parseColor } from './color'
Original file line number Diff line number Diff line change
Expand Up @@ -431,4 +431,25 @@ sequenceDiagram
},
])
})

it('can parse style clause', () => {
const example = stripStartEmptyLines(`
sequenceDiagram
@style noteTextColor #00bbaa
@style messageFontSize 20
`)
parse(example)
const ir = db.getDiagramIR()
// console.log(JSON.stringify(ir, null, 2))
expect(ir.styleParams).toMatchObject([
{
key: 'noteTextColor',
value: '#00bbaa',
},
{
key: 'messageFontSize',
value: '20',
},
])
})
})
15 changes: 9 additions & 6 deletions packages/pintora-diagrams/src/sequence/artist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
makeid,
configApi,
} from '@pintora/core'
import { db, SequenceDiagramIR, LINETYPE, Message, PLACEMENT, WrappedText, GroupAttrs } from './db'
import { db, SequenceDiagramIR, LINETYPE, Message, PLACEMENT, WrappedText } from './db'
import { SequenceConf, getConf } from './config'
import { getBaseNote, drawArrowTo, drawCrossTo, getBaseText, makeMark, makeLoopLabelBox } from './artist-util'
import { ITheme } from '../util/themes/base'
Expand Down Expand Up @@ -49,8 +49,8 @@ const GROUP_LABEL_MAP = {

const sequenceArtist: IDiagramArtist<SequenceDiagramIR> = {
draw(ir, config?) {
console.log('[draw]', ir)
conf = getConf()
// console.log('[draw]', ir)
conf = getConf(ir.styleParams)
theme = (configApi.getConfig() as DiagramsConf).themeConfig.themeVariables
model.init()
logger.debug(`C:${JSON.stringify(conf, null, 2)}`)
Expand All @@ -71,7 +71,7 @@ const sequenceArtist: IDiagramArtist<SequenceDiagramIR> = {
calcLoopMinWidths(ir.messages)
const maxMessageWidthPerActor = getMaxMessageWidthPerActor(ir)
model.maxMessageWidthPerActor = maxMessageWidthPerActor
conf.actorHeight = calculateActorMargins(actors, maxMessageWidthPerActor)
model.actorHeight = calculateActorMargins(actors, maxMessageWidthPerActor)

drawActors(rootMark, ir, { verticalPos: 0 })
const loopWidths = calculateLoopBounds(messages)
Expand Down Expand Up @@ -295,6 +295,8 @@ class Model {
/** backgrounds for groups like loop and opt */
groupBgs: Rect[]

actorHeight: number

private onBoundsFinishCbs: Array<OnBoundsFinishCallback>

init() {
Expand All @@ -312,6 +314,7 @@ class Model {
this.loopMinWidths = {}
this.onBoundsFinishCbs = []
this.groupBgs = []
this.actorHeight = conf.actorHeight
}
clear() {
this.activations = []
Expand Down Expand Up @@ -903,7 +906,7 @@ export const drawActors = function (
// Add some rendering data to the object
safeAssign(attrs, {
width: attrs.width || conf.actorWidth,
height: Math.max(attrs.height || 0, conf.actorHeight),
height: Math.max(attrs.height || 0, model.actorHeight),
margin: attrs.margin || conf.actorMargin,
x: prevWidth + prevMargin,
y: verticalPos,
Expand Down Expand Up @@ -971,7 +974,7 @@ export const drawActors = function (
}

// Add a margin between the actor boxes and the first arrow
model.bumpVerticalPos(conf.actorHeight)
model.bumpVerticalPos(model.actorHeight)
}

function drawActivationTo(mark: Group, data: ActivationData) {
Expand Down
13 changes: 9 additions & 4 deletions packages/pintora-diagrams/src/sequence/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MarkAttrs } from '@pintora/core'
import { PALETTE } from '../util/theme'
import { configApi, safeAssign } from '@pintora/core'
import { DiagramsConf } from '../type'
import { interpreteStyles, StyleParam } from '../util/style'

export type SequenceConf = {
noteWidth: number
Expand Down Expand Up @@ -84,13 +85,16 @@ export const defaultConfig: SequenceConf = {
showSequenceNumbers: false,
}

export const conf: SequenceConf = {
...defaultConfig,
}
export const SEQUENCE_STYLE_RULES = {
noteTextColor: { valueType: 'color' },
messageTextColor: { valueType: 'color' },
messageFontSize: { valueType: 'fontSize' },
} as const

export function getConf() {
export function getConf(styleParams: StyleParam[]) {
const globalConfig: DiagramsConf = configApi.getConfig()
const t = globalConfig.themeConfig.themeVariables
const conf = {...defaultConfig}
safeAssign(conf, {
actorBackground: t.primaryColor,
actorBorderColor: t.primaryBorderColor,
Expand All @@ -103,5 +107,6 @@ export function getConf() {
dividerTextColor: t.secondaryTextColor,
})
Object.assign(conf, globalConfig.sequence || {})
Object.assign(conf, interpreteStyles(SEQUENCE_STYLE_RULES, styleParams))
return conf
}
23 changes: 21 additions & 2 deletions packages/pintora-diagrams/src/sequence/db.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Group, logger, OrNull } from '@pintora/core'
import { parseColor } from '../util/color'
import { logger, OrNull, parseColor } from '@pintora/core'
import { StyleParam } from '../util/style'

export interface WrappedText {
text: string
Expand Down Expand Up @@ -91,6 +91,7 @@ export type SequenceDiagramIR = {
title: string
showSequenceNumbers: boolean
// titleWrapped: boolean
styleParams: StyleParam[]
}

class SequenceDB {
Expand All @@ -102,6 +103,7 @@ class SequenceDB {
titleWrapped: boolean = false
wrapEnabled = false
showSequenceNumbers = false
styleParams: SequenceDiagramIR['styleParams'] = []

addActor(id: string, name: string, description: ParsedDescription) {
// Don't allow description nulling
Expand Down Expand Up @@ -237,6 +239,10 @@ class SequenceDB {
return message
}

addStyle(sp: StyleParam) {
this.styleParams.push(sp)
}

getActor(id: string) {
return this.actors[id]
}
Expand All @@ -252,6 +258,7 @@ class SequenceDB {
this.actors = {}
this.title = ''
this.showSequenceNumbers = false
this.styleParams = []
}

getDiagramIR(): SequenceDiagramIR {
Expand All @@ -261,6 +268,7 @@ class SequenceDB {
actors: this.actors,
title: this.title,
showSequenceNumbers: this.showSequenceNumbers,
styleParams: this.styleParams,
}
}

Expand Down Expand Up @@ -306,6 +314,9 @@ class SequenceDB {
case 'addDivider':
db.addSignalWithoutActor({ text: param.text, wrap: false }, param.signalType)
break
case 'addStyle':
db.addStyle({ key: param.key, value: param.value })
break
}
}
}
Expand Down Expand Up @@ -339,6 +350,9 @@ export function enableSequenceNumbers() {
db.showSequenceNumbers = true;
}

/**
* action param that will be handled by `apply`
*/
type ApplyParam =
| {
type: 'addActor'
Expand Down Expand Up @@ -382,6 +396,11 @@ type ApplyParam =
signalType: LINETYPE
text: string
}
| {
type: 'addStyle'
key: string
value: string
}

export {
db
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@{%
import * as moo from 'moo'
import { tv, textToCaseInsensitiveRegex, VALID_TEXT_REGEXP } from '../../util/parser-shared'
import { tv, textToCaseInsensitiveRegex, VALID_TEXT_REGEXP, COLOR_REGEXP } from '../../util/parser-shared'

let lexer = moo.states({
main: {
Expand Down Expand Up @@ -44,6 +44,7 @@ export function setYY(v) {
@lexer lexer
@builtin "string.ne"
@builtin "whitespace.ne"
@include "../../util/parser-grammars/style.ne"

start -> __ start {% (d) => d[1] %}
| "sequenceDiagram" document __:? {%
Expand Down Expand Up @@ -148,6 +149,7 @@ statement ->
return { type: 'addDivider', text, signalType: yy.LINETYPE.DIVIDER }
}
%}
| styleClause _ %NEWLINE

words -> (%WORD | %SPACE):+ {%
function(d) {
Expand Down Expand Up @@ -271,5 +273,3 @@ par_sections ->
])
}
%}

color -> %COLOR {% (d) => tv(d[0]) %}
19 changes: 19 additions & 0 deletions packages/pintora-diagrams/src/util/parser-grammars/style.ne
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@{%
export const COLOR = /#[a-zA-Z0-9]+/
export const STYLE = /@style/
%}

color -> %COLOR {% (d) => tv(d[0]) %}

styleClause ->
%STYLE __ [a-zA-Z0-9]:+ __ [^ \n]:+ {%
function(d) {
// console.log('[styleClause]', d[2], JSON.stringify(d[4]))
const key = d[2].map(v => tv(v)).join('')
let value = d[4]
if (typeof value !== 'string') value = value.map(v => tv(v)).join('')
// console.log('[styleClause] result', key, value)
return { type: 'addStyle', key, value }
}
%}

6 changes: 5 additions & 1 deletion packages/pintora-diagrams/src/util/parser-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ export function textToCaseInsensitiveRegex(text) {

/** token value */
export function tv(token) {
return token.value
if (token && ('value' in token)) return token.value
return token
}

/** CJK friendly text pattern */
export const VALID_TEXT_REGEXP = /(?:[a-zA-Z0-9_]\p{Unified_Ideograph})+/

/** hex color */
export const COLOR_REGEXP = /#[a-zA-Z0-9]+/
6 changes: 6 additions & 0 deletions packages/pintora-diagrams/src/util/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { StyleParam, interpreteStyles } from '@pintora/core'

export {
StyleParam,
interpreteStyles,
}

0 comments on commit 1bf902c

Please sign in to comment.