Giter Site home page Giter Site logo

pragma's People

Contributors

dependabot[bot] avatar hexus avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

exside

pragma's Issues

Playground

Build a playground page with a YAML input for form definitions.

Would be fine to look a little like this with the form showing on the right.

Bundle runtime separately

Moved from README TODOs.

The Pragma runtime (primarily FormProcessor) is only bundled as a side effect of the example project.

Bundle it separately from the example project after clarifying the shape of Pragma's public API.

JSON Schema

Pragma's field definition format is similar to JSON Schema and JSON Editor.

Investigate the overlaps and consider switching over to, and extending, JSON Schema. This could be pretty powerful, but also a overcomplicated due to its extensive feature set (e.g. external references).

Really, the best thing about this approach would be type safety and validation. The worst thing would be potential complexity. Some of this complexity could be avoided if a simplified format could be processed into full JSON Schema.

We could then also provide a meta-schema for the field definitions themselves.

Examples of changes

Rough examples of what certain fields types look like now, and what they'd look like with JSON schema.

Before

profile:
  type: section
  label: Profile
  description: Character profile

profile.name:
  type: string
  label: Name
  description: The character's given or chosen name

profile.alignment:
  type: selection
  label: Alignment
  description: The character's general and moral attitude
  options:
    options:
      lawfulGood: Lawful Good
      neutralGood: Neutral Good
      chaoticGood: Chaotic Good
      lawfulNeutral: Lawful Neutral
      trueNeutral: True Neutral
      chaoticNeutral: Chaotic Neutral
      lawfulEvil: Lawful Evil
      neutralEvil: Neutral Evil
      chaoticEvil: Chaotic Evil

After

JSON Schema always defines the root, whereas Pragma currently implies one. We can still imply one, we just embed the form fields into the properties of a type: object.

type: object
title: Pathfinder Character Sheet
description: JSON Schema for Pragma forms for the Pathfinder roleplaying game.
properties:
  profile:
    type: object
    title: Profile
    description: Character profiles
    properties:
      name:
        type: string
        title: Name
        description: The character's given or chosen name
      alignment:
        type: string
        title: Alignment
        description: The character's general and moral attitude
        enum: [
          'lawfulGood', 'neutralGood', 'chaoticGood', 'lawfulNeutral', 'trueNeutral', 'chaoticNeutral',
          'lawfulEvil', 'neutralEvil', 'chaoticEvil'
        ]
        options: # This is where any Pragma-specific data would reside
          enumLabels: [
            'Lawful Good', 'Neutral Good', 'Chaotic Good', 'Lawful Neutral', 'True Neutral', 'Chaotic Neutral',
            'Lawful Evil', 'Neutral Evil', 'Chaotic Evil'
          ]

It's much more verbose, and introduces the nesting that Pragma's format tries to avoid, but we could find a middle ground that compiles to JSON schema. For example:

profile:
  type: object
  title: Profile
  description: Character profiles

profile.name:
  type: string
  title: Name
  description: The character's given or chosen name

profile.alignment:
  type: string
  title: Alignment
  description: The character's general and moral attitude
  enum: [
    'lawfulGood', 'neutralGood', 'chaoticGood', 'lawfulNeutral', 'trueNeutral', 'chaoticNeutral',
    'lawfulEvil', 'neutralEvil', 'chaoticEvil'
  ]
  options: # This is where any Pragma-specific data would reside
    enumLabels: [
      'Lawful Good', 'Neutral Good', 'Chaotic Good', 'Lawful Neutral', 'True Neutral', 'Chaotic Neutral',
      'Lawful Evil', 'Neutral Evil', 'Chaotic Evil'
    ]

What we avoid here is properties, or in the case of Pragma's current format: children. We instead rely on full paths like profile.alignment to set the expected properties for different objects.

tag, which is usually something like 'pragma-section' or 'pragma-string', could then become JSON Schema's/JSON Editor's format, which could translate to a theme of tag names to decide how to render.

Considering how such schemas might translate to a server-side implementation, however, this falls apart a bit. E.g. type: string and format: datetime, where a server-side representation might just see this instead as a Date type. However, this isn't too much of a problem, as we're specifying a JSON format.

Duplication

There's a lot of duplicated markup and some amounts of duplicated JavaScript.

  • Mitigate duplicate markup with more general custom tags and JavaScript-registered input event listeners
  • Mitigate duplicate JavaScript using Riot tag mixins where appropriate, either globally or via imports
  • Mitigate repetitive get/set paths between character sheets and character models; these need one source of truth

Web components

A set of web components could be used to either fully render a form, or selectively render parts of a form. Using field definitions for layout is then optional.

<pragma-form> would be a decorator element that propagates field data to any relevant children, internally managing a Pragma Form instance.

<pragma-form fields="..." data="...">
  <form>
    <div class="saves">
      <!-- Automatically render a subset of fields -->
      <pragma-fields path="defense.saves"/>
    </div>

    <!-- Manually lay out elements for fields -->
    <textarea name="defense.notes"></textarea>

    <!-- Define layout for field templates -->
    <template name="templates.spell">
      <div class="spell">
        <input type="text" name="templates.spell.name"/>
        <!-- ... -->
      </div>
    </template>
  </form>
</pragma-form>

<pragma-form> and <pragma-fields> elements could optionally load field sets by themselves.

<pragma-form src="/fields.json" data="...">
  <pragma-fields/>
</pragma>

<pragma-fields src="/fields.yaml" path="defense.saves"/>

Experiment with extending built-in elements

Moved from README TODOs

Web components can extend built-in HTML elements to inherit functionality and usability.

Stencil doesn't currently support this in any way, but a keen-eyed developer has found a workaround:

Try this out and see if the boilerplate repetition in the Pragma components can be reduced.

Note: This approach doesn't currently include form participation, but the same comment will be updated when the
developer gets around to it.

Processing maps

Propagation map

Denotes paths that should be copied to the keyed path. Cool. ๐Ÿ‘

Array values are iterated and the last non-null value is used.

Must be run before other maps, and other maps cannot use the same keys.

Customisable by merging in custom maps that users build into their sheets through the UI.

string or string[] values.

'defense.armorClass.abilityModifier': 'abilities.dex.modifier'

// or, for an outdated but relevant example of array values
'defense.armorClass.abilityModifier': ['abilities.dex.modifier', 'abilities.dex.tempModifier']

Summation map

Denotes paths that should be added to the keyed path... nice. โœŒ๏ธ

Customisable by merging in custom maps that users build into their sheets through the UI.

string or string[] values.

'armorClass.total': ['armorClass.armorBonus', 'armorClass.shieldBonus', 'armorClass...', ...]

Customisable by merging in custom maps that users could build into their sheets through the UI.

Interpolation map

Denotes fields with values that should be interpolated from other values... tight. ๐Ÿ‘Œ

A flattened set of character sheet properties could be passed to these as template arguments.

A select set of Lodash functions could be made available for utility, if needed.

This wouldn't be customisable, or maybe only in an advanced mode with an expression guide.

string values.

'*.spell.damage': '{class.level}d6'

Implemented

  • Propagation map
  • Summation map
  • Interpolation map

Operation order

Interpolating ability modifiers, for example, would require need to be interpolated prior to the propagation mapping. ๐Ÿค”

The right solution would involve checking which properties are used in which maps, resolving them backwards, depth first. Properties would be processed individually as part of being processed in a list. Determining these from interpolation maps would be especially fun... it'd have to be part of the interpolation process.

This would also involve keeping track of which have already been processed (removing those processed from a temporary copy of the relevant map).

Conclusion

A domain model suddenly seems less relevant!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.