Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/slaveofcode/jkt
Simple helper to parse JSON based on independent schema
https://github.com/slaveofcode/jkt
enum javascript jkt json json-enum json-struct json-structure json-types parser parsing struct
Last synced: about 2 months ago
JSON representation
Simple helper to parse JSON based on independent schema
- Host: GitHub
- URL: https://github.com/slaveofcode/jkt
- Owner: slaveofcode
- License: mit
- Created: 2018-01-24T14:57:26.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2022-12-30T20:14:07.000Z (about 2 years ago)
- Last Synced: 2024-11-10T16:47:58.293Z (2 months ago)
- Topics: enum, javascript, jkt, json, json-enum, json-struct, json-structure, json-types, parser, parsing, struct
- Language: JavaScript
- Homepage:
- Size: 278 KB
- Stars: 24
- Watchers: 2
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# JKT Parser
Simple helper to parse your JSON.
**UPDATE:** Take a look at `Podeng` a similar parser like JKT with richer features, go [visit the project here](https://github.com/slaveofcode/podeng)
* [JKT Parser](#jkt-parser)
* [Background](#background)
* [Requirements](#requirements)
* [Installing](#installing)
* [Running the tests](#running-the-tests)
* [API References](#api-references)
* [Struct](#struct)
* [Available Types](#available-types)
* [Instance of Struct](#instance-of-struct)
* [One Line vs Multi Line](#one-line-vs-multi-line)
* [Custom Predefined Value](#custom-predefined-value)
* [Extending Struct](#extending-struct)
* [Removing Parent Property](#removing-parent-property)
* [Check The Instance and Child](#check-the-instance-and-child)
* [Strict Types](#strict-types)
* [ENUM Value](#enum-value)
* [Nested Struct](#nested-struct)
* [Array Container](#array-container)
* [Custom Value Translator](#custom-value-translator)
* [Arrow Mapping Key -> Values](#arrow-mapping-key---values)
* [Struct & Instance References](#struct--instance-references)
* [Struct Property & Function](#struct-property--function)
* [Instance Function](#instance-function)
* [Author](#author)
* [License](#license)
* [Acknowledgments](#acknowledgments)## Background
At the first time I wonder how could I make my JSON to be more manageable. So confusing when every time I checking up the right parameters to my function, make sure the produced JSON data are valid and parsing all over the JSON properties to follow my rules (types).
Then I do research and no one module is available to fit in with my case, so I built this one.
**JKT** is a simple **Javascript** module to create a structure for your JSON. It's basically just a simple parser to handle property types, the structure and provide a small helper to handle the data.
### Requirements
To use JKT you need a NodeJS version `6.4.0` and up. Basically JKT really depends on ES6 style which using template literal in practice.
```
const jkt = require('jkt') // CommonJsconst Person = jkt`
name: String
age: Number
birthday: Date
hobbies: Array
`
```### Installing
As described before, you need NodeJs with version `6.4.0` and up before using this module. After that installing JKT is just simply as.
> Using NPM
```
npm i jkt --save
```> Using Yarn
```
yarn add jkt
```When finished you'll notice that this modules requires some libraries like `lodash`, `moment` and `shortid`.
## Running the tests
The test is very very simple, you just have to clone the project, do `npm install` and run `npm run test`, nothing special.
## API References
### Struct
You just have to define the JKT struct once and then you could rely on them. The struct is defined by using template literal.
```
const Person = jkt`
name: String
age: Number
birthday: Date
Hobbies: Array
`
```### Available Types
| Type | Description | Show on Invalid? | Show on JSON result |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | ------------------- |
| `String` | String type value | Yes | Yes |
| `String!` | Force to only accept string value | No | No |
| `Number` | Numeric type value, works for either Integer or Float | Yes | Yes |
| `Number!` | Force to only accept numeric value | No | No |
| `Boolean` | Boolean type value, works for either Integer or Float | Yes | Yes |
| `Boolean!` | Force to only accept boolean value | No | No |
| `Date` | Date type value that accept `ISO 8601`, supported by `Moment` and it is timezone aware (will convert to UTC time) based on your machine timezone | Yes | Yes |
| `Date!` | Force to only accept valid date value and will produce timezone aware date | No | No |
| `DatePlain` | Date type value that accept `ISO 8601`, supported by `Moment` and it is not timezone aware | Yes | Yes |
| `DatePlain!` | Force to only accept valid date value and will not produce timezone aware date | No | No |
| `Array` | Array type value | Yes | Yes |
| `Array!` | Force to only accept array value | No | No |
| `Object` | Object type value | Yes | Yes |
| `Object!` | Force to only accept object value | No | No |
| `Function` | Function type value | No | No |
| `Function!` | Force to only accept function | No | No |
| `ANY` | Any type value will be valid | Yes | Yes |### Instance of Struct
You can assume the `Person` as a structure for json data, then every time you do parsing, you just have to pass an argument into `Person`.
```
const aditya = Person({
name: "Aditya Kresna",
age: '26',
birthday: '1991-06-18' // ISO 8601
})// now aditya is the instance of Person
```Then you could use `aditya` properties or produce valid JSON format from it
```
aditya.name // "Aditya Kresna"
aditya.birthday // moment time
aditya.toJSON() // produce valid json format
aditya.j() // the shorthand method
```One thing that you should know is if JKT fails to identify type of the value, it will returning `null` as a default, except you use **force** type like `String!` and `Number!`
**[> See the result on RunKit](https://runkit.com/zeandcode/jkt-basic)**
### One Line vs Multi Line
There is a few method you can follow while making a struct, **One Line** and **Multi Line**. If you think your struct object is short and don't wanna make more space with using multi lines, you could simply create a struct separated by comma `,`.
```
const Animal = jkt`type: String, color: String, isWild: Boolean`
```or by multiple lines like this
```
const Animal = jkt`
type: String
color: String
isWild: Boolean
`const Animal2 = jkt`
type: String,
color: String,
beast: Boolean
`const Animal3 = jkt`
type: String!,
color: String!,
beast: Boolean
`
```**[> See the result on RunKit](https://runkit.com/zeandcode/jkt-one-line-vs-multi-line)**
### Custom Predefined Value
When you need to setup custom value upfront, without checking it's type or doing some validations, You could use it as a predefined value by put them inside of expression `${}`. Predefined value is the value you define when defining the struct.
```
const Mother = jkt`
name: String
birthday: Date
haveChild: ${true}
`const angela = Mother({
name: "Angela",
Birthday: "1990-06-06"
})const christy = Mother({
name: "Angela",
Birthday: "1990-06-06",
haveChild: false
})const Person = jkt`
name: String
sayTheWords: ${(words) => `Hi, ${words}`},
someOptions: ${{some: "options"}}
`const aditya = Person({
name: "Aditya"
})angela.haveChild // true
christy.haveChild // falseaditya.sayTheWords('How are you') // "Hi, How are you"
aditya.j()
// { name: "Aditya", someOptions: { some: "options" } }
```**[> See the result on RunKit](https://runkit.com/zeandcode/custom-predefined-value)**
You could pass anything you want, but if you pass a `function` for example, it will not showing on the output when you calling `toJSON` or `j` function, because the value wasn't a valid JSON type.
### Extending Struct
Once you define a struct it possible to extend into another struct.
```
const Person = jkt`
name: String
age: Number
hobby: Array
birthday: Date
`const Driver = Person`
useBike: Boolean
useCar: Boolean
`const Doctor = Person`
specialist: String
hospitalLocation: String
`
```**[> See the result on RunKit](https://runkit.com/zeandcode/extending-struct)**
Both of `Driver` and `Doctor` is a child of `Person`, so you will get the `name`, `age`, `hobby` and `birthday` properties when you do parse of the `driver` and `doctor` instance.
### Removing Parent Property
Sometimes we want to extend from existing struct but on a few situation we don't wanna include some properties. By using `!DELETE` we can exclude the property when extending from existing struct.
```
const Person = jkt`
name: String
age: Number
hobby: Array
drinkBeer: Boolean
`const Child = Person`
toys: Array
drinkBeer: !DELETE // this "drinkBeer" will be deleted on child struct
`
```**[> See the result on RunKit](https://runkit.com/zeandcode/removing-parent-property)**
### Check The Instance and Child
It is also possible to checking the instance and child.
```
const Person = jkt`
name: String
age: Number
hobby: Array
`
const Child = Person`
toys: Array
doingHomework: Boolean
`const Mother = Person`
singleParent: Boolean
`const John = Child({
name: "John Doe"
})Child.childOf(Person) // true
Mother.childOf(Person) // trueJohn.instanceOf(Person) // true
John.instanceOf(Child) // true
```**[> See the result on RunKit](https://runkit.com/zeandcode/check-the-instance-and-child)**
### Strict Types
As mentioned before (on a table), every unsupplied value or invalid type would make the property have `null` value when parsed. But we can force the property to not exist when invalid value raised.
```
const Person = jkt`
name: String
age: Number!
hobby: Array!
`const John = Person({ name: "John Doe", age: "not sure"})
John.j() // { name: "John Doe" }
```**[> See the result on RunKit](https://runkit.com/zeandcode/strict-types)**
### ENUM Value
We often need to reference some value based on it's own defined types. This could be done with `ENUM`, where ENUM is a feature when we need some property to strictly follow the type as we defined on ENUM itself.
```
const Colors = jkt.ENUM`
RED: Maroon
WHITE
BLUE: ${'just blue'}
`const TSize = jkt.ENUM`small, medium, large, extra_large: ${'EXTRA-LARGE'}`
const TShirt = jkt`
model: String
brand: Number!
color: ${Colors}
size: ${TSize}
`// Calling enum directly
Colors() // { RED: 'Maroon', WHITE: 'WHITE', BLUE: 'just blue' }TSize() // { SMALL: 'SMALL', MEDIUM: 'MEDIUM', LARGE: 'LARGE', EXTRA_LARGE: 'EXTRA-LARGE' }
// Callling enum from struct using "E" property
TShirt.E.COLOR.RED // "Maroon"
```**[> See the result on RunKit](https://runkit.com/zeandcode/enum-value)**
The `E` stands for the collection of the ENUM on `TShirt`. If you want to see complete values of ENUM just take the `E` property.
All enum properties and value would be converted to **Upper-Case** string (even if it's a number), it doesn't accept any special characters except underscore `_` and If you want to set custom value just use an expression `${}`.
### Nested Struct
Every single struct we define is an independent structure that could be used with another struct. By this point you got a very reusable component as you may need the same structure on another struct (eg. as a collection).
```
const Person = jkt`
name: String
age: Number
birthday: Date
`const SchoolClass = jkt`
name: String
grade: Number
teacher: ${Person}
`// show the schema
SchoolClass.schema/**
{
name: "String",
grade: "Number",
teacher: {
name: "String",
age: "Number",
birthday: "Date"
}
}
*/const mySchoolClass = SchoolClass({
name: 'Awesome Class',
grade: '10',
teacher: {
name: 'Amelia',
age: 25,
birthday: '1992-05-31' // ISO 8601
}
})mySchoolClass.j()
/**
{ name: "Awesome Class",
grade: 10,
teacher: {
name: "Amelia",
age: 25,
birthday: "1992-05-30T17:00:00.000Z"
}
}
*/
```**[> See the result on RunKit](https://runkit.com/zeandcode/nested-struct)**
### Array Container
Container to keep our struct inside json array.
```
const Person = jkt`
name: String
age: Number
birthday: Date
`const SchoolClass = jkt`
name: String
grade: Number
students: ${jkt.c.array(Person)}
`const strictNull = false // if some value has null, the item will not added into list
const defaultToArray = true // set default value to array ( not null )
const People = jkt.array(Person, strictNull, defaultToArray)const listOfPeople = People([
{
name: 'Aditya',
age: '27',
birthday: '1991-06-18',
},
{
name: 'John',
age: '20',
birthday: '1996-10-04',
},
])
```**[> See the result on RunKit](https://runkit.com/zeandcode/array-container)**
### Custom Value Translator
With all of provided parsers, I believe there is always not enough to cover up our desired types. So here's translator comes in.
```
const Person = jkt`
name: String
age: Number
birthday: ${jkt.trans.custom(val => "I'm old man =,=")}
`const nina = Person({
name: "Nina",
age: "25",
birthday: new Date() // this will produce "I'm old man =,="
});nina.birthday // "I'm old man =,="
nina.j().birthday // "I'm old man =,="
```**[> See the result on RunKit](https://runkit.com/zeandcode/translator-custom-value)**
### Arrow Mapping Key -> Values
With mapping you could reuse key-value on supplied json to make your own custom key based on that source.
```
const Person = jkt`
name: String
name->full_name: String // mapping from source key (name) to new key (full_name)
address: String
address->address2: String // mapping from source key (address) to new key (address2)
age: Number
age->ageInString: String // mapping from source key (age) to new key (ageInString) with type String
`const aditya = Person({
name: "Aditya",
age: "27",
address: "Kota Bekasi"
});aditya.name // "Aditya"
aditya.full_name // "Aditya"
aditya.address2 // "Kota Bekasi"
aditya.age // 27
aditya.ageInString // "27"
```**[> See the result on RunKit](https://runkit.com/zeandcode/arrow-mapping)**
### Struct & Instance References
These are detailed function & properties you could use when using jkt struct. You shouldn't use the following reserved words as a property for your struct, because it was reserved to support the module.
### Struct Property & Function
| Name | Type | Description |
| ---------- | -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `isJKT` | Boolean (true) | Nothing special about this, just used to to identify JKT struct on internal parser. |
| `schema` | JSON | Schema of struct, you could inspect this property after defining the struct. |
| `childOf` | Function | To check if the struct is a child of the given struct |
| `__id` | String | The id of struct, every struct has an unique id generated based on `shortid` library |
| `__schema` | JSON | The dirty schema of the struct which used internally to parse value |
| `E` | JSON | A container of all enum values on the struct, this property only available when we set some property with `ENUM` type. |### Instance Function
| Name | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `instanceOf` | To identify the instance of struct |
| `getSchema` | To get struct schema from the instance |
| `getDirtySchema` | To get the real struct schema from the instance. The result including the function and properties to do parse inside the module |
| `toJSON` | To get valid json from the instance. |
| `j` | To get valid json from the instance. This is a shorthand method of `toJSON` |
| `toString` | To get json string from the instance. |## Author
* **Aditya Kresna Permana** - _Indonesia_ - [SlaveOfCode](https://github.com/slaveofcode)
## License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
## Acknowledgments
* This module may have some limitation based on reserved naming of the methods and properties
* Highly inspired with styled-components style
* This module may still buggy, make a pull request or make an issue if you found them.