{"id":13607819,"url":"https://github.com/redgeoff/mson","last_synced_at":"2025-04-12T18:44:14.348Z","repository":{"id":37850714,"uuid":"143070968","full_name":"redgeoff/mson","owner":"redgeoff","description":"🏗️MSON Lang: Generate an app from JSON","archived":false,"fork":false,"pushed_at":"2024-01-02T17:12:04.000Z","size":6572,"stargazers_count":473,"open_issues_count":21,"forks_count":33,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-04-04T00:07:08.911Z","etag":null,"topics":["app-generator","javascript","json","material-ui","mson","programming-language","react","validation"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redgeoff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-07-31T21:14:21.000Z","updated_at":"2025-02-05T20:52:30.000Z","dependencies_parsed_at":"2024-01-07T21:02:06.669Z","dependency_job_id":null,"html_url":"https://github.com/redgeoff/mson","commit_stats":{"total_commits":1576,"total_committers":6,"mean_commits":262.6666666666667,"dds":0.2899746192893401,"last_synced_commit":"728218c8105647e78e3e9c1e976e5ec2ef0ad13c"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redgeoff%2Fmson","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redgeoff%2Fmson/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redgeoff%2Fmson/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redgeoff%2Fmson/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redgeoff","download_url":"https://codeload.github.com/redgeoff/mson/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248617199,"owners_count":21134190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app-generator","javascript","json","material-ui","mson","programming-language","react","validation"],"created_at":"2024-08-01T19:01:21.880Z","updated_at":"2025-04-12T18:44:14.325Z","avatar_url":"https://github.com/redgeoff.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# \u003cimg src=\"https://raw.githubusercontent.com/redgeoff/mson/main/mson.png\" alt=\"MSON\" width=\"30\" height=\"30\" /\u003e MSON\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/redgeoff/mson/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/redgeoff/mson/tree/main)\n\nThe MSON compiler allows you to generate apps from JSON. The ultimate goal of MSON is to allow anyone to develop software visually, but you can also use pieces of MSON to turbo charge your development:\n\n  - MSON is a subset of JSON and comprised of just a few building blocks, yet it is as powerful as its non-declarative counterparts. MSON supports validation, inheritance, composition, pub/sub, access control, templating and various other features.\n\n  - MSON is particularly useful in software that generates other software, e.g. a form builder. This is because MSON is just JSON, so it is easy to consume, modify and store.\n\n  - MSON is framework agnostic, but the default [mson-react](https://github.com/redgeoff/mson-react) rendering layer uses React and Material-UI to generate a UI. The rendering layer is pluggable and can be written to support any framework and UI library.\n\n  - The MSON library can also be used without any UI dependecies, which makes it great for things like data validation in both the front and back ends.\n\nYou can read more about why I created MSON at [Creating a New Programming Language That Will Allow Anyone to Make Software](https://redgeoff.com/posts/everyone-can-make-software/).\n\n## Live Demo\n\n\u003ca href=\"https://redgeoff.github.io/mson-react\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/redgeoff/mson-react/master/demo.png\" alt=\"MSON Demo\" /\u003e\u003c/a\u003e\n\n## Getting Started\n\n### Demo Apps on Codesandbox\n\nCheck out the [To Do List](https://codesandbox.io/s/mson-to-do-list-qcn7p) and [Basic App](https://codesandbox.io/s/mson-basic-app-x0d3z), which will let you play with MSON in real-time.\n\n### Getting Started App\n\nThe best way to get started with MSON is to play with the [Getting Started App](https://github.com/redgeoff/mson-getting-started). In just a few lines of MSON, you'll generate an app that can list, edit, filter and sort a list of contacts. And, for extra fun, you can use Firebase to make it real-time capable.\n\n### Autogenerate forms in React and Material-UI with MSON\nImplementing great forms can be a real time-waster. With just a few lines of JSON, you can [use MSON to generate forms](https://redgeoff.com/posts/mson-react-material-ui-form/) that perform real-time validation and have a consistent layout.\n\n### MSON Demo\n\nAfter you have played with the Getting Started App you may find it useful to fire up the [MSON demo](https://redgeoff.github.io/mson-react):\n\n  - $ `git clone https://github.com/redgeoff/mson-react \u0026\u0026 cd mson-react \u0026\u0026 yarn install`\n  - $ `yarn start`\n  - Visit http://localhost:3000 in a web browser\n\nThe MSON code can be found in [components](https://github.com/redgeoff/mson-react/tree/master/src/demo/components). Here are some highlights:\n  1. [List of Contacts](https://github.com/redgeoff/mson-react/blob/master/src/demo/components/contacts.js)\n  2. [Editing with a RecordEditor](https://github.com/redgeoff/mson-react/blob/master/src/demo/components/edit-contact.js)\n  3. [List of Fields](https://github.com/redgeoff/mson-react/blob/master/src/demo/components/fields.js)\n  4. [Displaying Markdown](https://github.com/redgeoff/mson-react/blob/master/src/demo/components/home.js)\n\n## Language Principles\n\n### Declarative Syntax\nMSON is short for Model Script Object Notation, which is intentionally similar to JSON (JavaScript Object Notation). In fact, MSON is a subset of JSON, so if you know JSON then you know the syntax of MSON!\n\nDeclarative languages are much easier for software to read and write as they define what the software must do without stating exactly how to do it. And JSON is a great foundation on which to build. It contains just a few main constructs, is ubiquitous and supported by a vast ecosystem.\n\n### Components\nThe smallest building block in MSON is called a component. Components maintain state and can also control presentation and are very similar to the components now commonplace in most web frameworks. Components can inherit, contain or wrap other components. The rendering layer supports plugins for different environments and the default plugin supports React and Material-UI. Use of the rendering layer is optional, so components can be used on both the front end and back end.\n\nA simple form component used to collect a name and email address could look like:\n```js\n{\n  name: 'MyForm',\n  component: 'Form',\n  fields: [\n    {\n      name: 'name',\n      component: 'TextField',\n      label: 'Name',\n      required: true\n    },\n    {\n      name: 'email',\n      component: 'EmailField',\n      label: 'Email'\n    },\n    {\n      name: 'submit',\n      component: 'ButtonField',\n      label: 'Submit',\n      icon: 'CheckCircle'\n    }\n  ]\n}\n```\n\nThe majority of the remaining examples in this post will focus on form components, as they are simple to visualize, but MSON can support any type of component, e.g. menus, snackbars, redirects, etc… In addition, you can use JavaScript to create user-defined components that can pretty much do anything else you can imagine.\n\n### Validators\nEach field has a default set of validators, e.g. the EmailField ensures that email addresses are in a valid format. You can also extend these validators for a particular field or even for an entire form.\n\nFor example, you can prevent the user from entering _nope@example.com_:\n```js\n{\n  name: 'MyForm',\n  component: 'Form',\n  fields: ...,\n  validators: [\n    {\n      where: {\n        'fields.email.value': 'nope@example.com'\n      },\n      error: {\n        field: 'email',\n        error: 'must not be {{fields.email.value}}'\n      }\n    }\n  ]\n}\n```\nTemplate parameters like `{{fields.email.value}}` can be used to inject the values of fields. And, you can use any [MongoDB-style query](https://docs.mongodb.com/manual/reference/operator/query/) in the `where`. For example, if you had `password` and `retypePassword` fields, you could ensure that they are equivalent with:\n```js\nwhere: {\n  'retypePassword.fields.value': {\n    $ne: '{{fields.password.value}}'\n  }\n}\n```\n\n### Events \u0026 Listeners\n\nChanges to properties in a component generate events and you can create listeners that respond to these events with actions. There are basic actions that set, emit, email, contact APIs, etc… and custom actions can also be built using JavaScript.\n\nThe following example sets the value of the `email` field based on the value supplied in the `name` field when the user clicks the `submit` button:\n```js\n{\n  name: 'MyForm',\n  component: 'Form',\n  fields: ...,\n  validators: ...,\n  listeners: [\n    {\n      event: 'submit',\n      actions: [\n        {\n          component: 'Set',\n          name: 'fields.email.value',\n          value: '{{fields.name.value}}@example.com'\n        }\n      ]\n    }\n  ]\n}\n```\nWe can also make this action conditional, e.g. only set the `email` if it is blank:\n```js\nlisteners: [\n  {\n    event: 'submit',\n    actions: [\n      {\n        component: 'Set',\n        if: {\n          'fields.email': {\n            $or: [\n              {\n                value: null\n              },\n              {\n                value: ''\n              }\n            ]\n          }\n        },\n        name: 'fields.email.value',\n        value: '{{fields.name.value}}@example.com'\n      }\n    ]\n  }\n]\n```\nAnd sometimes we want to nest actions so that a condition is met before all actions are executed:\n```js\nlisteners: [\n  {\n    event: 'submit',\n    actions: [\n      {\n        component: 'Action',\n        if: {\n          'fields.email': {\n            $or: [\n              {\n                value: null\n              },\n              {\n                value: ''\n              }\n            ]\n          }\n        },\n        actions: [\n          {\n            component: 'Set',\n            name: 'fields.email.value',\n            value: '{{fields.name.value}}@example.com'\n          },\n          {\n            component: 'Set',\n            name: 'fields.name.value',\n            value: '{{fields.name.value}} Builder'\n          }\n        ]\n      }\n    ]\n  }\n]\n```\n\n### Template Queries\n\nIt is possible to chain together a series of actions to accomplish almost anything. The downside to this approach is that your code can quickly become bloated and you may be required to create a number of custom actions. Consider an example where we want to increment the value of a counter if the counter is not null. Assume that we have a custom component called `Increment`, which increments values and does not work with null values:\n\n```js\n{\n  name: 'MyForm',\n  component: 'Component',\n  schema: {\n    component: 'Form',\n    fields: [\n      { name: 'counter', component: 'IntegerField' }\n      { name: 'submit', component: 'ButtonField' }\n    ]\n  },\n  listeners: [\n    {\n      event: 'submit',\n      if: {\n        'fields.counter.value': null\n      },\n      actions: [\n        {\n          // The counter is null so assume it is now 1\n          component: 'Set',\n          name: 'fields.counter.value',\n          value: 1\n        }\n      ],\n      else: [\n        {\n          // Assume Increment doesn't work with null values\n          component: 'Increment',\n          value: '{{fields.counter.value}}'\n        },\n        {\n          component: 'Set',\n          name: 'fields.counter.value',\n          // Output of the Increment action above is available at {{arguments}}\n          value: '{{arguments}}'\n        }\n      ]\n    }\n  ]\n}\n```\n\nInstead, with Template Queries, we can use [MongoDB-style aggregation operators](https://docs.mongodb.com/manual/reference/operator/aggregation/#expression-operators) to accomplish this functionality in fewer lines of code:\n\n```js\n{\n  name: 'MyForm',\n  component: 'Component',\n  schema: ...,\n  listeners: [\n    {\n      event: 'submit',\n      actions: [\n        {\n          component: 'Set',\n          name: 'fields.counter.value',\n          value: {\n            $cond: [\n              { $eq: ['{{fields.counter.value}}', null] },\n              1, // Initial increment\n              { $add: ['{{fields.counter.value}}', 1] } // Subsequent increment\n            ]\n          }\n        }\n      ]\n    }\n  ]\n}\n```\n\nNote: MSON just uses the same syntax as MongoDB, but does not require or depend on MongoDB.\n\nYou can use Template Queries to execute custom routines with many other [useful operators](https://docs.mongodb.com/manual/reference/operator/aggregation/#expression-operators) like `$add`, `$multiply`, `$filter` and `$map`. And, you can make these routines reusable by wrapping them in a [custom Action](https://github.com/redgeoff/mson/wiki/Reusable-Custom-Actions).\n\n### Access Control\n\nUnlike most programming languages, access control is a first-class citizen in MSON, so its easy to use without a lot of work. Access can be restricted at the form or field layers for the create, read, update and archive operations. (MSON is designed to encourage data archiving instead of deletion so that data can be restored when it is accidentally archived. You can, of course, permanently delete data when needed).\n\nEach user can have any number of user-defined roles and access is then limited to users with specified roles. There is also a system role of owner that is defined for the `owner` of the data. Field-layer access is checked first and if it is missing it will cascade to checking the form-layer access. When the access is undefined at the form layer (and not defined at the field-layer), all users have access.\n\nHere is an example configuration:\n```js\n{\n  name: 'MyForm',\n  component: 'Form',\n  fields: ...,\n  validators: ...,\n  listeners: ...,\n  access: {\n    form: {\n      create: ['admin', 'manager'],\n      read: ['admin', 'employee'],\n      update: ['admin', 'owner', 'manager'],\n      archive: ['admin']\n    },\n    fields: {\n      name: {\n        create: ['admin'],\n        update: ['owner']\n      }\n    }\n  }\n}\n```\nAmong other things, only users with the `admin` or `manager` roles can create records. In addition, only owners of a record can modify the `name`.\n\n### Inheritance\n\nInheritance is used to add additional functionality to a component. For example, we can extend `MyForm` and add a phone number:\n```js\n{\n  name: 'MyFormExtended',\n  component: 'MyForm',\n  fields: [\n    {\n      name: 'phone',\n      component: 'PhoneField',\n      label: 'Phone Number',\n      before: 'submit'\n    }\n  ]\n}\n```\nWe can define new validators, listeners, access, etc… at this new layer. For example, we can pre-populate some data, lay out all fields on the same line and disable the email field by creating a listener for the `create` event:\n```js\n{\n  name: 'MyFormExtended',\n  component: 'MyForm',\n  fields: ...,\n  listeners: [\n    {\n      event: 'create',\n      actions: [\n        {\n          component: 'Set',\n          name: 'value',\n          value: {\n            name: 'Bob Builder',\n            email: 'bob@example.com',\n            phone: '(206)-123-4567'\n          }\n        },\n        {\n          component: 'Set',\n          name: 'fields.name.block',\n          value: false\n        },\n        {\n          component: 'Set',\n          name: 'fields.email.block',\n          value: false\n        },\n        {\n          component: 'Set',\n          name: 'fields.email.disabled',\n          value: true\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Template Parameters\n\nTemplate parameters are helpful when creating reusable components as they allow you to make pieces of your component dynamic. For example, let’s say that we want our first field and the label of our second field to be dynamic:\n```js\n{\n  name: 'MyTemplatedForm',\n  component: 'Form',\n  fields: [\n    '{{firstField}}',\n    {\n      name: 'secondField',\n      label: '{{secondFieldLabel}}',\n      component: 'EmailField'\n    }\n  ]\n}\n```\nwe can then extend `MyTemplatedForm` and fill in the pieces:\n```js\n{\n  name: 'MyFilledTemplatedForm',\n  component: 'MyTemplatedForm',\n  firstField: {\n    name: 'firstName',\n    component: 'TextField',\n    label: 'First Name'\n  },\n  secondFieldLabel: 'Email Address'\n}\n```\n\n### Composition\n\nThe `componentToWrap` property allows you to wrap components, enabling your reusable components to transform any component. For example, we can use composition to create a reusable component that adds a phone number:\n```js\n{\n  name: 'AddPhone',\n  component: 'Form',\n  componentToWrap: '{{baseForm}}',\n  fields: [\n    {\n      name: 'phone',\n      component: 'PhoneField',\n      label: 'Phone Number',\n      before: 'submit'\n    }\n  ]\n}\n```\nand then pass in a component to be wrapped:\n```js\n{\n  name: 'MyFormWithPhone',\n  component: 'AddPhone',\n  baseForm: {\n    component: 'MyForm'\n  }\n}\n```\nYou can even extend wrapped components, paving the way for a rich ecosystem of aggregate components comprised of other components.\n\n### Aggregate Components\n\nMSON ships with a number of aggregate components such as the `RecordEditor` and `RecordList`, which make it easy to turn your form components into editable UIs with just a few lines of code.\n\nLet’s define a user component:\n```js\n{\n  name: 'MyAccount',\n  component: 'Form',\n  fields: [\n    {\n      name: 'firstName',\n      component: 'TextField',\n      label: 'First Name'\n    },    \n    {\n      name: 'lastName',\n      component: 'TextField',\n      label: 'Last Name'\n    },\n    {\n      name: 'email',\n      component: 'EmailField',\n      label: 'Email'\n    }\n  ]\n}\n```\nwe can then use a `RecordEditor` to allow the user to edit her/his account:\n```js\n{\n  name: 'MyAccountEditor',\n  component: 'RecordEditor',\n  baseForm: {\n    component: 'MyAccount'\n  },\n  label: 'Account'\n}\n```\nYou can also use the `RecordList` to display an editable list of these accounts:\n```js\n{\n  name: 'MyAccountsList',\n  component: 'RecordList',\n  label: 'Accounts',\n  baseFormFactory: {\n    component: 'Factory',\n    product: {    \n      component: 'MyAccount'\n    }\n  }\n}\n```\n\n### Schemas and Self Documentation\n\nSchemas must be defined for all components, which means that MSON is strongly typed. For example, a schema that defines boolean and date properties may look like:\n```js\n{\n  name: 'MyComponent',\n  component: 'Component',\n  schema: {\n    component: 'Form',\n    fields: [\n      {\n        name: 'hidden',\n        component: 'BooleanField',\n        help: 'Whether or not the component is hidden'\n      },\n      {\n        name: 'updatedAt',\n        component: 'DateTimeField',\n        required: true, \n        help: 'When the component was updated'\n      }\n    ]\n  }\n}\n```\nSchemas can also contain documentation via `help` properties, which means that components are self-documenting! In addition, schemas are inherited and can be overwritten to allow for more or even less constraints.\n\n### User-Defined JavaScript Components\n\nThe MSON compiler is written in JavaScript and can run in both the browser and in Node.js. As such, you can use any custom JS, including external JS libraries, to create your own components.\n\nFor example, here is a component that uses [Moment.js](https://momentjs.com/) to set a `currentDay` property to the current day:\n```js\nimport compiler from 'mson/lib/compiler';\nimport Component from 'mson/lib/component';\nimport Form from 'mson/lib/form';\nimport { TextField } from 'mson/lib/fields';\nimport moment from 'moment';\n\nclass MyComponent extends Component {\n  // className is needed as JS minification strips the constructor name\n  className = 'MyComponent';\n\n  create(props) {\n    super.create(props);\n\n    this.set({\n      // Define a currentDay property\n      schema: new Form({\n        fields: [\n          new TextField({\n            name: 'currentDay'\n          })\n        ]\n      }),\n\n      // Default currentDay\n      currentDay: moment().format('dddd')\n    });\n  }\n}\n\ncompiler.registerComponent('MyComponent', MyComponent);\n```\nAnd then `MyComponent` can be used in any MSON code.\n\nYou can also do things like define custom asynchronous actions, e.g. one that POSTs form data:\n```js\nimport compiler from 'mson/lib/compiler';\nimport Action from 'mson/lib/actions/action';\nimport Form from 'mson/lib/form';\nimport { TextField } from 'mson/lib/fields';\n\nclass MyAction extends Action {\n  className = 'MyAction';\n\n  create(props) {\n    super.create(props);\n\n    this.set({\n      schema: new Form({\n        fields: [\n          new TextField({\n            name: 'foo'\n          })\n        ]\n      })\n    });\n  }\n\n  async act(props) {\n    const form = new FormData();\n    form.append('foo', this.get('foo'));\n\n    const account = props.component;\n    form.append('firstName', account.get('firstName');\n    form.append('lastName', account.get('lastName');\n    form.append('email', account.get('email');\n    \n    return fetch({\n      'https://api.example.com',\n      {\n        method: 'POST',\n        body: form\n      }\n    })\n  }\n}\ncompiler.registerComponent('MyAction', MyAction);\n```\nAnd then you can use this in your MSON code:\n```js\n{\n  name: 'MyAccountExtended',\n  component: 'MyAccount',\n  listeners: [\n    {\n      event: 'submit',\n      actions: [\n        {\n          component: 'MyAction',\n          foo: 'bar'\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Using MSON in Any JavaScript Code\n\nThere is always parity between compiled and uncompiled components so that the same feature set is supported by both compiled and uncompiled code. For example, our same `MyAccount` component can also be defined as:\n\n```js\nimport Form from 'mson/lib/form';\nimport { TextField, Email } from 'mson/lib/fields';\n\nclass MyAccount extends Form {\n  // className is needed as JS minification strips the constructor name\n  className = 'MyAccount';\n\n  create(props) {\n    super.create(props);\n    this.set({\n      fields: [\n        new TextField({\n          name: 'firstName',\n          label: 'First Name'\n        }),\n        new TextField({\n          name: 'lastName',\n          label: 'Last Name'\n        }),\n        new EmailField({\n          name: 'email',\n          label: 'Email'\n        })\n      ]\n    })\n  }\n}\n```\nIn fact, converting MSON code to this type of code is basically what the compiler does. Although, the compiler doesn’t actually transpile MSON to JS, it merely instantiates JS code based on the MSON definitions.\n\nSince all MSON code can be compiled to JS code, you can use MSON components in any JS code. For example, you can set some fields and validate the data:\n```js\nimport compiler from 'mson/lib/compiler';\n\n// Compile the MyAccount component\nconst CompiledMyAccount = compiler.compile({\n  component: MyAccount\n});\n\n// Instantiate the JS class with a default value\nconst myAccount = new CompiledMyAccount({\n  // Default values\n  value: {\n    firstName: 'Bob'\n  }\n});\n\n// Set the remaining data\nmyAccount.set({\n  lastName: 'Builder',\n  email: 'invalid-email@'\n});\n\n// Make sure the values are valid\nmyAccount.validate();\nif (myAccount.hasErr()) {\n  console.log(myAccount.getErrs());\n}\n```\nIn other words, you can use MSON in your existing JS code to save time writing complex code. By declaring components in MSON, you’ll remove a lot of boilerplate code and reduce the possibility of bugs. You’ll also have code that has a standard structure and is framework agnostic. And this code doesn’t add any unneeded frameworks or back-end dependencies to your codebase.\n\n### Component as a Class or Compiled Component\n\nIn the above example, we used:\n```js\nconst CompiledMyAccount = compiler.compile({\n  component: MyAccount\n});\n```\nwhereby, `MyAccount` is actually a class (compiled component). This can be handy as it means that we didn't have to register `MyAccount` with the compiler and we can import components using the native constructs present in JavaScript. On the other hand, our definition:\n```js\n{\n  component: MyAccount\n}\n```\ncan no longer be serialized into a JSON string as it references a JavaScript class. JSON serialization could be a requirement if, for example, we want to store our definitions in a database. MSON gives you the freedom to make this decision as you can always use the following instead:\n```js\ncompiler.registerComponent('MyAccount', MyAccount);\n\nconst CompiledMyAccount = compiler.compile({\n  component: 'MyAccount'\n});\n```\n\n### Reusing MSON Code Throughout the Full Stack\n\nMSON components can be shared by both the front end and back end, allowing for key logic to be written once and then reused. For example, the same form validation rules can be enforced in the browser and by your back-end API.\n\nMoreover, actions can be limited to the `backEnd` or `frontEnd`, so that the same component can adjust according to the host environment. For example, you may want a contact form to send an email to the user when it is used on the back end, but only display a [snackbar](https://material-ui.com/demos/snackbars/) on the front end:\n```js\n{\n  component: 'Form',\n  fields: [\n    {\n      name: 'email',\n      component: 'EmailField',\n      label: 'Email'\n    },\n    {\n      name: 'message',\n      component: 'TextField',\n      label: 'Message'\n    },\n    {\n      name: 'Submit',\n      component: 'ButtonField',\n      label: 'Submit'\n    }\n  ],\n  listeners: [\n    {\n      event: 'submit',\n      actions: [\n        {\n          // Send an email on the back end\n          component: 'Email',\n          layer: 'backEnd',\n          from: '{{fields.email.value}}',\n          to: 'noreply@example.com',\n          subject: 'My message',\n          body: '{{fields.message.value}}',\n          // Detach so that user doesn't have to wait for email\n          // to send\n          detach: true\n        },\n        {\n          // Display a message to the user on the front end\n          component: 'Snackbar',\n          layer: 'frontEnd',\n          message: 'Thanks for the message'\n        }\n      ]\n    }\n  ]\n}\n```\n\n### In/Out Properties\n\nSometimes you want the presence of data, but don’t want it to be written or read from the back end. For example, your default user component may not allow for the password to be read or edited:\n```js\n{\n  name: 'MyUser',\n  component: 'Form',\n  fields: [\n    {\n      name: 'name',\n      component: 'TextField',\n      label: 'Name'\n    },\n    {\n      name: 'email',\n      component: 'EmailField',\n      label: 'Email'\n    },\n    {\n      name: 'password',\n      component: 'PasswordField',\n      label: 'Password',\n      hidden: true,\n      in: false,\n      out: false\n    }\n  ]\n}\n```\nHowever, your `EditPasswordForm` may need to allow such access:\n```js\n{\n  name: 'EditPasswordForm',\n  component: 'MyUser',\n  listeners: [\n    {\n      event: 'create',\n      actions: [\n        {\n          // Hide all fields\n          component: 'Set',\n          name: 'hidden',\n          value: true\n        },\n        {\n          // Show password field\n          component: 'Set',\n          name: 'fields.password.hidden',\n          value: false\n        },\n        {\n          // Allow user to write password to the back end\n          component: 'Set',\n          name: 'fields.password.out',\n          value: true\n        }\n      ]\n    }\n  ]\n}\n```\n\n## [MSON Design](DESIGN.md)\nCheck out [MSON Design](DESIGN.md) for more info on why certain conventions were chosen.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredgeoff%2Fmson","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredgeoff%2Fmson","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredgeoff%2Fmson/lists"}