xogroup / felicity Goto Github PK
View Code? Open in Web Editor NEWJavascript object constructors and sample data based on Joi schema.
License: Other
Javascript object constructors and sample data based on Joi schema.
License: Other
The following test fails:
describe('generating example for number with max', () => {
it('should not hang', done => {
const FelicityConstructor = Felicity.entityFor(Joi.number().max(1));
const felicityInstance = new FelicityConstructor();
const example = felicityInstance.example();
expect(example).to.be.a.number();
done();
});
})
A successful test result
The code hanging. Seems to be this while
-loop that doesn't terminate.
I somehow overlooked the fact that Joi v10 was added as a peerDep. Is that needed since Joi is a direct dependency?
Integrate this repo with NSP
Using the Joi sample schema of:
let schema = Joi.object().keys({
username: Joi.string().alphanum().min(3).max(30).required(),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email()
}).with('username', 'birthyear').without('password', 'access_token');
Node returns:
> const felicityInstance = new Felicity.skeleton(schema);
TypeError: Cannot read property 'type' of undefined
at childrenKeys.forEach (/Users/dhinkle/Work/felicity/lib/joiGenerator.js:47:37)
at Array.forEach (native)
at schemaMapper (/Users/dhinkle/Work/felicity/lib/joiGenerator.js:35:30)
at skeleton.generate (/Users/dhinkle/Work/felicity/lib/joiGenerator.js:83:5)
at new skeleton (/Users/dhinkle/Work/felicity/lib/index.js:13:18)
at repl:1:26
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:96:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:313:29)
The validate
method return object should include the value of the validated object with any applicable Joi type conversions, regardless of success/failure:
{
success: true,
errors : null,
value : {/*...*/}
}
@WesTyler I've made a PR to support value generation of this API.
With the release of Joi v10, there are 2 new methods to implement: Joi.boolean().truthy()
and Joi.boolean().falsy()
Example value generation should have basic support array-typed schema.
Joi v10.0.0 has been released. Let's jump on board.
Using the Joi schema Joi.object().pattern()
should be supported in both .entityFor
and .example
methods.
const schema = Joi.object().pattern(/^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$/, Joi.object().keys({
id : Joi.string().guid().required(),
tags: Joi.array().items(Joi.string()).required()
})).min(2);
const example = Felicity.example(schema);
example
/*
{
'4dffdb09-9e60-423d-b956-a9b821fb8fde': {
id: '4dffdb09-9e60-423d-b956-a9b821fb8fde',
tags: []
},
'3ad38506-3ef4-4e93-a745-023f8e8ccf75': {
id: '3ad38506-3ef4-4e93-a745-023f8e8ccf75',
tags: []
}
}
*/
Only the .min(2)
is respected. Example fails validation.
example
/*
{
wdgx: 'wdgx6obscdnbrtz9kldavpldi',
ppfz: 'ppfzbv353bdllftgdzllq5mi'
}
*/
There are some assumptions Felicity makes, such as stamping default values in and stripping optional properties out.
Both Felicity.skeleton
and Felicity.example
should take an optional configuration object to toggle these defaults as needed.
Create a shared NPM shared group account for us to start deploying OSS projects to. Also configure TravisCI to make the build and push with.
This is a forum to discuss support and implementation of Joi extensions.
In order to maintain a 1:1 api parity with Joi, we will eventually need some level of support for Joi extensions.
It's important to note in thinking about implementation that extensions do not modify the Joi module itself, but provide a new Joi instance to the consumer. Felicity will not be able to pick up extensions automagically through Joi because of this fact. So we will need some sort of dynamic behavior for example
and entityFor
around customized schema types/extensions.
Should handle Joi.string().regex()
properly and return a string that matches the provided regex pattern.
This is not likely to be 100% coverage for all possible regex patterns, but basic support should at least be there.
Look at https://github.com/fent/randexp.js for implementation ideas.
Should handle Joi.object().with()
and Joi.object().without()
properly and return an object with the expected key set.
Generate an example for a schema with alternatives, where one of the alternatives is an object.
const Felicity = require('felicity');
const Joi = require('joi');
const schema = Joi.alternatives().try(
Joi.string(),
Joi.object({ en: Joi.string(), es: Joi.string() })
);
Felicity.example(schema);
The error only shows up when the object schema is chosen as the alternative for the example.
I expected a valid example for the object schema to be generated.
Refactor all anonymous function declarations to use () => {}
syntax. Should help with readability of the overall code base. But let's not refactor any function
declaration with name associations such as function namedFunction()
. But if possible, replaced those with let namedFunction = () => {}
When valid-shaped input with invalid values is provided to a constructor function from Felicity.entityFor, the values should not be stripped out of the input. Only unknown/disallowed keys should be stripped out of the input.
const schema = Joi.object().keys({
id: Joi.string().guid().required()
});
const Document = Felicity.entityFor(schema);
const input = { id: '1234567890', notes: [] };
const document = new Document(input); // { id: '1234567890' }
const schema = Joi.object().keys({
id: Joi.string().guid().required()
});
const Document = Felicity.entityFor(schema);
const input = { id: '1234567890', notes: [] };
const document = new Document(input); // { id: null }
With the release of Joi (v10)[https://github.com/hapijs/joi/issues/1037], there is a new string regex option to implement:
Travis build is failing due to <100% test coverage. Just adding an issue for this to promote transparency.
Just creating a place to track with Joi schema features we currently support.
A feature/option is "supported" when there are explicit tests in both Felicity.skeleton and Felicity.example.
Joi version: 9.0.4
default
✅required
✅optional
✅valid
✅allow
✅strip
✅forbidden
✅guid
✅email
✅min
✅max
✅length
✅isoDate
✅regex
✅
invert: true
❌insensitive
✅truncate
✅creditCard
✅replace
✅alphanum
✅token
✅ip
✅uri
❌uuid
✅hex
✅hostname
✅lowercase
✅uppercase
✅trim
✅negative
✅positive
✅integer
✅min
✅max
✅greater
✅less
✅precision
✅multiple
✅truthy
✅falsy
✅encoding
✅min
✅max
✅length
✅min
✅
now
✅max
✅
now
✅iso
✅timestamp
✅
unix
✅format
✅arity(1)
✅arity
✅minArity
✅maxArity
✅ref
❌items
✅
forbidden
✅sparse
✅ordered
✅min
✅max
✅length
✅single
✅unique
❌try
✅when
✅keys
✅min
✅max
✅length
✅nand
✅xor
✅with
✅without
✅pattern
❌and
✅or
✅rename
✅unknown
✅type
✅schema
✅requiredKeys
❌optionalKeys
❌Example value generation should have basic support for binary-typed schema.
const schema = Joi.object({
alternative: Joi.alternatives().try(Joi.number().integer().min(1), Joi.string().guid().lowercase()).required()
});
const Document = Felicity.entityFor(schema);
const doc = new Document();
/* Error: Cannot read property 'type' of undefined
at childrenKeys.forEach (/[redacted]/felicity/lib/joiGenerator.js:72:33)
at Array.forEach (native)
at schemaMapper (/[redacted]/felicity/lib/joiGenerator.js:52:26)
at Constructor.generate (/[redacted]/felicity/lib/joiGenerator.js:93:5)
at new Constructor /[redacted]/felicity/lib/index.js:88:22)
*/
The document should be instantiated with the alternative
key set to null
.
Error: Cannot read property 'type' of undefined
Create /examples
directory with several different use-cases. With test coverage.
Should handle Joi.string().email() properly and return a valid (but fake) email address.
Allow .example
methods to accept an input parameter. Valid input will be used instead of randomly-generated data.
const schema = Joi.object().keys({
people: Joi.object().pattern(/^[0-9a-fA-F]{8}$/, Joi.object().keys({
id : Joi.string().guid().required(),
tags: Joi.array().items(Joi.string())
})).min(2).required()
});
const Pairing = Felicity.entityFor(schema);
const commonPerson = {
people: {
adc7d80c: {
id: 'adc7d80c-f78c-44f1-94c6-73e816f5aa84',
tags: ['admin']
}
}
};
const semiRandom = Pairing.example(commonPerson);
/*
{
people: {
adc7d80c: {
id: 'adc7d80c-f78c-44f1-94c6-73e816f5aa84',
tags: ['admin']
},
0ac079ea: {
id: '0ac079ea-e92e-4d41-b6b5-ed493008e807',
tags: ['da34fad']
}
}
}
*/
Example value generation should have basic support function-typed schema.
We need some documentation around testing.
Re-write README to follow standards of Hapi.js outlined here.
Example value generation should have basic support alternatives-typed schema.
Felicity should provide a simple API for creating custom constructor functions from a schema.
Both returned Constructor and instances of Constructor should have the validate
and example
methods
const schema = Joi.object().keys({});
const Conversation = Felicity.builder(schema);
const conversation = new Conversation();
const mockConversation = conversation.example(); // or Conversation.example()
const validation = conversation.validate(); // or Conversation.validate(input)
Currently, Felicity.example
will always pick a random value from the valids
array if present. This means that some schema that .allow(null)
will always generate null
.
const schema = Joi.object().keys({
name: Joi.string().allow(null)
});
Felicity.example(schema); // always returns { name: null }
Instead, the code should only sometimes use valids
unless flags.allowOnly
is set in which case the current behavior is correct.
Joi.string().allow(null).describe();
// { type: 'string', valids: [ null ], invalids: [ '' ] }
Joi.string().valid('name').describe();
// { type: 'string', flags: { allowOnly: true }, valids: [ 'name' ], invalids: [ '' ] }
The below should be accurate. Right now, passing strictExample
to entityFor
does not persist the config for future .example()
calls on instances.
strictExample
- default false
. Default behavior is to not run examples through Joi validation before returning.If set to true
, example will be validated prior to returning.
Note: in most cases, there is no difference. The only known cases where this may result in no example coming back are with regex patterns containing lookarounds.
const schema = Joi.object().keys({
name : Joi.string().regex(/abcd(?=efg)/)
});
const instance = new (Felicity.entityFor(schema)); // instance === { name: null }
const mockInstance = instance.example(); // mockInstance === { name: 'abcd' }
const strictInstance = new (Felicity.entityFor(schema, { config: { strictExample: true } })); strictInstance === { name: null }
const mockStrict = strictInstance.example(); // ValidationError
Failed tests:
11) Felicity Example should return a buffer:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at Object.exampleGenerator [as example] (/Users/lchan/Projects/felicity/lib/exampleGenerator.js:16:138)
at /Users/lchan/Projects/felicity/test/felicity_tests.js:92:34
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
84) Binary should return a buffer:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:514:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
85) Binary should return a string with specified encoding:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:534:44
at Array.forEach (native)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:531:28
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
86) Binary should return a buffer of minimum size:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:546:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
87) Binary should return a buffer of maximum size:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:554:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
88) Binary should return a buffer of specified size:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:562:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
89) Binary should return a buffer of size between min and max:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:571:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
122) Object should return an object with specified keys:
Buffer.alloc is not a function
at Object.internals.string.internals.number.internals.binary.schema [as binary] (/Users/lchan/Projects/felicity/lib/helpers.js:323:110)
at /Users/lchan/Projects/felicity/lib/helpers.js:499:147
at Array.forEach (native)
at Object.internals.string.internals.number.internals.binary.internals.date.internals.array.internals.object.Object.keys.forEach.schemaDescription.rules.forEach.schemaDescription.dependencies.forEach.peers.forEach [as object] (/Users/lchan/Projects/felicity/lib/helpers.js:483:126)
at /Users/lchan/Projects/felicity/test/value_generator_tests.js:960:40
at Immediate._onImmediate (/Users/lchan/Projects/felicity/node_modules/lab/lib/runner.js:647:36)
at processImmediate [as _immediateCallback] (timers.js:383:17)
8 of 131 tests failed
Test duration: 389 ms
Assertions count: 1575 (verbosity: 12.02)
No global variable leaks detected
Coverage: 99.87% (1/754)
lib/helpers.js missing coverage on line(s): 329
Code coverage below threshold: 99.87 < 100
Linting results: No issues
npm ERR! Test failed. See above for more details.
https://github.com/xogroup/felicity/blob/master/lib/joiGenerator.js#L54
Only Hoek.reach
once, then compare to the two values to assign flags.
This release breaks previous return values from Felicity.example()
for some combinations of Joi.number()
schema.
Felicity.example()
In v1, Felicity had hard-coded checks for "impossible" scenarios (like Joi.number().negative().min(1)
), and would return NaN
. Because of some bad mathematical assumptions in those hard-coded checks, some cases like Joi.number().negative().max(10)
were considered "impossible" incorrectly.
Felicity now uses Joi.validate()
inside of the example generation of numbers to determine "impossible" status. This means some examples that were previously (incorrectly) considered impossible will now return valid numbers.
Felicity.example(Joi.number().negative().max(10));
// OLD:
// NaN
// NEW:
// some psuedo-random negative number
Felicity.example(Joi.number().multiple(12).max(10));
// OLD:
// NaN
// NEW:
// 0
Please leave any comments, questions, concerns, advice, etc regarding the API.md documentation.
Feel free to make a PR to rewrite anything you want, but please tag the commit/PR with this issue so that I can see what was changed in one central spot. I like to learn and improve. :)
Travis CI. But PRs should automatically trigger the npm test
command and show if there are failing tests, uncovered paths, and/or basic linting issues.
I'm trying to generate an example from a joi schema. Something as simple as this
const Felicity = require('felicity');
const ProbeSchema = require('./path/to/schema');
console.log(Felicity.example(ProbeSchema));
But I'm getting the following error:
/node_modules/felicity/lib/helpers.js:615
const child = new Examples[childSchema.type](childSchemaRaw, childOptions);
I expect an auto generated example, of course 😄
Instead I get an error.
I think this may be related with #80
Is felicity unable to generate examples from extended Joi instances?
Regards
Add doctoc
to devDeps.
Add updateTOC
npm script.
Ensure API.md has the expected doctoc comments in place for auto-updates.
There is a ton of duplicate logic and checking in the example data generation code base at /lib/helpers
. This also creates complex edge cases (like #111 ).
The example data generation should leverage classes so that base Joi rules like defaults, valids, examples, etc can be abstracted into the base Example class. Each "type" can then handle type-specific rules more cleanly, and "meta" types like alternatives
and object
keys do not have to re-create raw schema and parse the rules/defaults/flags all over again.
To reproduce, create a constructor functions from a Joi schema using Felicity.entityFor()
, then call .validate((err, result) => {})
on a new instance of the constructor.
According to API.md, the callback should receive a single parameter that is the same validation object as is returned by .validate()
with no callback.
The callback function receives 2 parameters, following the standard Node.js callback signature (err, result) => {}
. The API.md documentation should be updated to reflect this behavior.
Constructor functions created by Felicity.entityFor
currently have the constructor name Constructor
. There should be an option available to entityFor
to override this name.
> const User = Felicity.entityFor(Joi.object(), { config: { constructorName: 'User' } })
> new User()
User {}
> const User = Felicity.entityFor(Joi.object())
> new User()
Constructor {}
Pending approval/implementation of hapijs/joi#1026 , the Felicity lib/helpers.js/internals.object
method should not rely on _inner
properties anymore.
Once again following Hapi.js patterns:
create /images
directory in repo root; drop png
(s).
README: ![felicity Logo](https://raw.github.com/xogroup/felicity/master/images/felicity.png)
Example value generation should have basic support object-typed schema.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.