shapeshifter
Advanced tools
Comparing version 2.3.0 to 3.0.0
@@ -26,3 +26,3 @@ #! /usr/bin/env node | ||
alias: 'n', | ||
description: 'Mark attributes as nullable by default (flow). Default false.', | ||
description: 'Mark attributes as nullable by default (recommended). Defaults to false.', | ||
type: Boolean, | ||
@@ -32,11 +32,4 @@ defaultValue: false, | ||
{ | ||
name: 'required', | ||
alias: 'r', | ||
description: 'Mark attributes as required by default (react, typescript). Default false.', | ||
type: Boolean, | ||
defaultValue: false, | ||
}, | ||
{ | ||
name: 'indent', | ||
description: 'The indentation characters to use. Default 2 space indent.', | ||
description: 'The indentation characters to use. Defaults to 2 space indent.', | ||
typeLabel: '[underline]{char}', | ||
@@ -48,3 +41,3 @@ type: String, | ||
name: 'format', | ||
description: 'The format to generate. Accepts react, flow, or typescript. Default react.', | ||
description: 'The format to generate. Accepts react, flow, or typescript. Defaults to react.', | ||
typeLabel: '[underline]{name}', | ||
@@ -56,3 +49,3 @@ type: String, | ||
name: 'schemas', | ||
description: 'Include schema class exports in the output. Default false.', | ||
description: 'Include schema class exports in the output. Defaults to false.', | ||
type: Boolean, | ||
@@ -63,3 +56,3 @@ defaultValue: false, | ||
name: 'attributes', | ||
description: 'Include an attribute list in the schema class export. Default false.', | ||
description: 'Include an attribute list in the schema class export. Defaults to false.', | ||
type: Boolean, | ||
@@ -70,3 +63,3 @@ defaultValue: false, | ||
name: 'types', | ||
description: 'Include type definition exports in the output. Default false.', | ||
description: 'Include type definition exports in the output. Defaults to false.', | ||
type: Boolean, | ||
@@ -109,4 +102,3 @@ defaultValue: false, | ||
new Transpiler({ | ||
defaultNull: options.nullable, | ||
defaultRequired: options.required, | ||
defaultNullable: options.nullable, | ||
includeSchemas: options.schemas, | ||
@@ -113,0 +105,0 @@ includeAttributes: options.attributes, |
@@ -0,1 +1,12 @@ | ||
# 3.0.0 | ||
* Added GraphQL support through the use of `.gql` files to read from (instead of JSON). | ||
* Updated TypeScript requirement to v2.0 and Flowtype to v0.30. | ||
* Replaced Mocha + Chai with Jest and increased code coverage to 100%. | ||
* Merged `null` and `required` flags into a single `nullable` field used by all formats. | ||
* Removed `function` type definition support. | ||
* Removed `nullable` support from TypeScript; use TypeScript's `--strictNullChecks` instead. | ||
* Renamed `SchemaReader` to `Schematic` and all instances of the word reader (like variables). | ||
* Renamed and split `Factory` into `DefinitionFactory` and `RendererFactory`. | ||
* Fixed an issue in which nullable flags could not be passed to enum value types. | ||
# 2.3.0 | ||
@@ -6,3 +17,3 @@ * Added a new shape reference feature, which allows for local reusable shapes in a JSON schema. | ||
# 2.2.2 | ||
* Added flowtype definitions to the `libs/` output folder. | ||
* Added Flowtype definitions to the `libs/` output folder. | ||
* Updated develop dependency TypeScript to v2.0. | ||
@@ -32,3 +43,3 @@ | ||
* React type suffix is now `Shape`. | ||
* Flow type suffix is now `Type`. | ||
* Flowtype type suffix is now `Type`. | ||
* TypeScript type suffix is now `Interface`. | ||
@@ -35,0 +46,0 @@ * Removed global `config.js` object file. Configuration options are now |
@@ -13,3 +13,3 @@ 'use strict'; | ||
var PRIMITIVE_TYPES /*: string[]*/ = exports.PRIMITIVE_TYPES = ['boolean', 'number', 'string']; | ||
var COMPOUND_TYPES /*: string[]*/ = exports.COMPOUND_TYPES = ['array', 'enum', 'instance', 'object', 'shape', 'union', 'function', 'reference']; | ||
var COMPOUND_TYPES /*: string[]*/ = exports.COMPOUND_TYPES = ['array', 'enum', 'instance', 'object', 'shape', 'union', 'reference']; | ||
var TYPES /*: string[]*/ = exports.TYPES = PRIMITIVE_TYPES.concat(COMPOUND_TYPES); |
@@ -45,4 +45,3 @@ 'use strict'; | ||
this.config = (0, _extends3.default)({ | ||
null: options.defaultNull, | ||
required: options.defaultRequired | ||
nullable: options.defaultNullable | ||
}, config); | ||
@@ -63,18 +62,6 @@ | ||
value: function isNullable() /*: boolean*/ { | ||
return this.config.null; | ||
return this.config.nullable; | ||
} | ||
/** | ||
* Returns true if the attribute is required. | ||
* | ||
* @returns {Boolean} | ||
*/ | ||
}, { | ||
key: 'isRequired', | ||
value: function isRequired() /*: boolean*/ { | ||
return this.config.required; | ||
} | ||
/** | ||
* Validate the definition configuration. | ||
@@ -88,9 +75,5 @@ */ | ||
if (typeof config.null !== 'boolean') { | ||
throw new TypeError('Invalid type detected, "null" property must be a boolean.'); | ||
if (typeof config.nullable !== 'boolean') { | ||
throw new TypeError('Invalid type detected, "nullable" property must be a boolean.'); | ||
} | ||
if (typeof config.required !== 'boolean') { | ||
throw new TypeError('Invalid type detected, "required" property must be a boolean.'); | ||
} | ||
} | ||
@@ -97,0 +80,0 @@ }]); |
@@ -35,5 +35,5 @@ 'use strict'; | ||
var _Factory = require('../Factory'); | ||
var _DefinitionFactory = require('../DefinitionFactory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _DefinitionFactory2 = _interopRequireDefault(_DefinitionFactory); | ||
@@ -75,3 +75,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
this.valueType = _Factory2.default.definition(this.options, this.attribute, valueType); | ||
this.valueType = _DefinitionFactory2.default.factory(this.options, this.attribute, valueType); | ||
} | ||
@@ -78,0 +78,0 @@ }]); |
@@ -89,2 +89,3 @@ 'use strict'; | ||
})) { | ||
/* istanbul ignore next This is tested but Istanbul won't pick up */ | ||
throw new TypeError('Enum values do not match the defined value type.'); | ||
@@ -104,11 +105,4 @@ } | ||
value: function validateValue(value /*: mixed*/) /*: boolean*/ { | ||
var valueType = (0, _normalizeType2.default)(this.config.valueType); | ||
// Function names are defined as strings within the schema | ||
if (valueType === 'function') { | ||
valueType = 'string'; | ||
} | ||
// eslint-disable-next-line valid-typeof | ||
return (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === valueType; | ||
return (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === (0, _normalizeType2.default)(this.config.valueType); | ||
} | ||
@@ -115,0 +109,0 @@ }]); |
@@ -39,5 +39,5 @@ 'use strict'; | ||
var _Factory = require('../Factory'); | ||
var _DefinitionFactory = require('../DefinitionFactory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _DefinitionFactory2 = _interopRequireDefault(_DefinitionFactory); | ||
@@ -90,4 +90,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
this.keyType = _Factory2.default.definition(this.options, this.attribute + '_key', keyType); | ||
this.valueType = _Factory2.default.definition(this.options, this.attribute + '_value', valueType); | ||
// Object keys should never be null | ||
this.keyType = _DefinitionFactory2.default.factory(this.options, this.attribute + '_key', { | ||
type: keyType, | ||
nullable: false | ||
}); | ||
// Values can be anything | ||
this.valueType = _DefinitionFactory2.default.factory(this.options, this.attribute + '_value', valueType); | ||
} | ||
@@ -94,0 +100,0 @@ }]); |
@@ -39,5 +39,5 @@ 'use strict'; | ||
var _Factory = require('../Factory'); | ||
var _DefinitionFactory = require('../DefinitionFactory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _DefinitionFactory2 = _interopRequireDefault(_DefinitionFactory); | ||
@@ -91,3 +91,3 @@ var _isObject = require('../helpers/isObject'); | ||
this.attributes = (0, _keys2.default)(attributes).map(function (attribute) { | ||
return _Factory2.default.definition(_this2.options, attribute, attributes[attribute]); | ||
return _DefinitionFactory2.default.factory(_this2.options, attribute, attributes[attribute]); | ||
}); | ||
@@ -94,0 +94,0 @@ } else { |
@@ -35,5 +35,5 @@ 'use strict'; | ||
var _Factory = require('../Factory'); | ||
var _DefinitionFactory = require('../DefinitionFactory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _DefinitionFactory2 = _interopRequireDefault(_DefinitionFactory); | ||
@@ -78,3 +78,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
this.valueTypes = valueTypes.map(function (type, i) { | ||
return _Factory2.default.definition(_this2.options, _this2.attribute + '_' + i, type); | ||
return _DefinitionFactory2.default.factory(_this2.options, _this2.attribute + '_' + i, type); | ||
}); | ||
@@ -81,0 +81,0 @@ } |
@@ -7,8 +7,9 @@ 'use strict'; | ||
exports.default = normalizeType; | ||
/** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
var _isObject = require('./isObject'); | ||
var _isObject2 = _interopRequireDefault(_isObject); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// Use a hash map for faster lookups | ||
@@ -18,3 +19,2 @@ var ALIAS_MAP = { | ||
bool: 'boolean', | ||
func: 'function', | ||
inst: 'instance', | ||
@@ -40,3 +40,14 @@ int: 'number', | ||
*/ | ||
/** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
function normalizeType(type /*: mixed*/) /*: string*/ { | ||
if ((0, _isObject2.default)(type)) { | ||
// $FlowIssue We know its an object | ||
type = type.type; | ||
} | ||
type = String(type).toLowerCase(); | ||
@@ -43,0 +54,0 @@ |
@@ -11,2 +11,10 @@ 'use strict'; | ||
var _from = require('babel-runtime/core-js/array/from'); | ||
var _from2 = _interopRequireDefault(_from); | ||
var _set = require('babel-runtime/core-js/set'); | ||
var _set2 = _interopRequireDefault(_set); | ||
var _extends2 = require('babel-runtime/helpers/extends'); | ||
@@ -32,6 +40,2 @@ | ||
var _Factory = require('./Factory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _Definition = require('./Definition'); | ||
@@ -41,2 +45,6 @@ | ||
var _DefinitionFactory = require('./DefinitionFactory'); | ||
var _DefinitionFactory2 = _interopRequireDefault(_DefinitionFactory); | ||
var _Schema = require('./Schema'); | ||
@@ -46,5 +54,5 @@ | ||
var _SchemaReader = require('./SchemaReader'); | ||
var _Schematic = require('./Schematic'); | ||
var _SchemaReader2 = _interopRequireDefault(_SchemaReader); | ||
var _Schematic2 = _interopRequireDefault(_Schematic); | ||
@@ -63,6 +71,2 @@ var _Array = require('./definitions/Array'); | ||
var _Func = require('./definitions/Func'); | ||
var _Func2 = _interopRequireDefault(_Func); | ||
var _Instance = require('./definitions/Instance'); | ||
@@ -110,8 +114,2 @@ | ||
/** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: import type { | ||
@@ -124,11 +122,16 @@ Options, | ||
ImportStructure, | ||
} from './types';*/ | ||
} from './types';*/ /** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: type TemplateList = string[];*/ | ||
var Renderer = function () { | ||
function Renderer(options /*: Options*/, reader /*: SchemaReader*/) { | ||
function Renderer(options /*: Options*/, schematic /*: Schematic*/) { | ||
(0, _classCallCheck3.default)(this, Renderer); | ||
this.options = options; | ||
this.reader = reader; | ||
this.schematic = schematic; | ||
this.suffix = ''; | ||
@@ -141,3 +144,2 @@ this.imports = []; | ||
this.relations = []; | ||
this.referencePaths = []; | ||
} | ||
@@ -280,14 +282,2 @@ | ||
/** | ||
* Return a list of all relative reference paths. | ||
* | ||
* @returns {String[]} | ||
*/ | ||
}, { | ||
key: 'getReferences', | ||
value: function getReferences() /*: TemplateList*/ { | ||
return this.referencePaths; | ||
} | ||
/** | ||
* Return the export name to be used as the prop type or type alias name. | ||
@@ -371,3 +361,3 @@ * | ||
var constants = this.reader.constants; | ||
var constants = this.schematic.constants; | ||
@@ -389,3 +379,3 @@ | ||
this.reader.imports.forEach(function (statement /*: ImportStructure*/) { | ||
this.schematic.imports.forEach(function (statement /*: ImportStructure*/) { | ||
_this2.imports.push(_this2.renderImport(statement)); | ||
@@ -401,10 +391,4 @@ }); | ||
key: 'parseReferences', | ||
value: function parseReferences() { | ||
var _this3 = this; | ||
value: function parseReferences() {} | ||
(0, _keys2.default)(this.reader.references).forEach(function (key /*: string*/) { | ||
_this3.referencePaths.push(_this3.reader.references[key]); | ||
}); | ||
} | ||
/** | ||
@@ -421,6 +405,6 @@ * Parse out all schemas. | ||
var _reader = this.reader, | ||
attributes = _reader.attributes, | ||
name = _reader.name, | ||
metadata = _reader.metadata; | ||
var _schematic = this.schematic, | ||
attributes = _schematic.attributes, | ||
name = _schematic.name, | ||
metadata = _schematic.metadata; | ||
@@ -443,3 +427,3 @@ | ||
value: function parseSets() { | ||
var _this4 = this; | ||
var _this3 = this; | ||
@@ -450,7 +434,7 @@ if (!this.options.includeTypes) { | ||
var baseAttributes = this.reader.data.attributes; | ||
var _reader2 = this.reader, | ||
attributes = _reader2.attributes, | ||
subsets = _reader2.subsets, | ||
name = _reader2.name; | ||
var baseAttributes = this.schematic.data.attributes; | ||
var _schematic2 = this.schematic, | ||
attributes = _schematic2.attributes, | ||
subsets = _schematic2.subsets, | ||
name = _schematic2.name; | ||
@@ -467,4 +451,3 @@ // Subsets | ||
var nullable = subset.null || {}; | ||
var required = subset.required || {}; | ||
var nullable = subset.nullable || {}; | ||
@@ -474,2 +457,3 @@ subset.attributes.forEach(function (attribute /*: string*/) { | ||
/* istanbul ignore next Hard to test */ | ||
if (!setConfig) { | ||
@@ -486,13 +470,9 @@ throw new SyntaxError('Attribute ' + attribute + ' does not exist in the base schema.'); | ||
if (attribute in nullable) { | ||
setConfig.null = nullable[attribute]; | ||
setConfig.nullable = nullable[attribute]; | ||
} | ||
if (attribute in required) { | ||
setConfig.required = required[attribute]; | ||
} | ||
setAttributes.push(_Factory2.default.definition(_this4.options, attribute, setConfig)); | ||
setAttributes.push(_DefinitionFactory2.default.factory(_this3.options, attribute, setConfig)); | ||
}); | ||
_this4.sets.push(_this4.render(_this4.getObjectName(name, setName, _this4.suffix), setAttributes)); | ||
_this3.sets.push(_this3.render(_this3.getObjectName(name, setName, _this3.suffix), setAttributes)); | ||
}); | ||
@@ -511,7 +491,7 @@ | ||
value: function parseShapes() { | ||
var _this5 = this; | ||
var _this4 = this; | ||
var _reader3 = this.reader, | ||
name = _reader3.name, | ||
shapes = _reader3.shapes; | ||
var _schematic3 = this.schematic, | ||
name = _schematic3.name, | ||
shapes = _schematic3.shapes; | ||
@@ -521,6 +501,6 @@ | ||
var attributes = (0, _keys2.default)(shapes[key]).map(function (attribute) { | ||
return _Factory2.default.definition(_this5.options, attribute, shapes[key][attribute]); | ||
return _DefinitionFactory2.default.factory(_this4.options, attribute, shapes[key][attribute]); | ||
}); | ||
_this5.sets.push(_this5.render(_this5.getObjectName(name, key, _this5.suffix), attributes)); | ||
_this4.sets.push(_this4.render(_this4.getObjectName(name, key, _this4.suffix), attributes)); | ||
}); | ||
@@ -560,4 +540,2 @@ } | ||
return this.renderEnum(definition, depth); | ||
} else if (definition instanceof _Func2.default) { | ||
return this.renderFunc(definition, depth); | ||
} else if (definition instanceof _Instance2.default) { | ||
@@ -604,3 +582,3 @@ return this.renderInstance(definition, depth); | ||
value: function renderArrayItems(items /*: PrimitiveType[]*/) /*: string[]*/ { | ||
var _this6 = this; | ||
var _this5 = this; | ||
@@ -611,3 +589,3 @@ var depth /*: number*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
return items.map(function (item) { | ||
return _this6.wrapItem(_this6.formatValue(item, valueType), depth); | ||
return _this5.wrapItem(_this5.formatValue(item, valueType), depth); | ||
}); | ||
@@ -627,9 +605,11 @@ } | ||
value: function renderArrayDefinitions(items /*: Definition[]*/) /*: string[]*/ { | ||
var _this7 = this; | ||
var _this6 = this; | ||
var depth /*: number*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
return items.map(function (item) { | ||
return _this7.wrapItem(_this7.renderAttribute(item, depth), depth); | ||
}); | ||
var set = new _set2.default(items.map(function (item) { | ||
return _this6.wrapItem(_this6.renderAttribute(item, depth), depth); | ||
})); | ||
return (0, _from2.default)(set.values()); | ||
} | ||
@@ -658,7 +638,7 @@ | ||
value: function renderConstant(name /*: string*/, value /*: PrimitiveType | PrimitiveType[]*/) /*: string*/ { | ||
var _this8 = this; | ||
var _this7 = this; | ||
if (Array.isArray(value)) { | ||
value = this.formatArray(value.map(function (v) { | ||
return _this8.formatValue(v); | ||
return _this7.formatValue(v); | ||
}), 0, ', ', ''); | ||
@@ -683,12 +663,2 @@ } else { | ||
/** | ||
* Render a function definition. | ||
*/ | ||
}, { | ||
key: 'renderFunc', | ||
value: function renderFunc(definition /*: FuncDefinition*/, depth /*: number*/) /*: string*/ { | ||
return this.unsupported('function'); | ||
} | ||
/** | ||
* Render an import statement. | ||
@@ -774,3 +744,3 @@ * | ||
value: function renderObjectProps(props /*: Definition[]*/) /*: string[]*/ { | ||
var _this9 = this; | ||
var _this8 = this; | ||
@@ -781,3 +751,3 @@ var depth /*: number*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
return props.map(function (prop) { | ||
return _this9.wrapProperty(_this9.wrapPropertyName(prop), _this9.renderAttribute(prop, depth), depth, sep); | ||
return _this8.wrapProperty(_this8.wrapPropertyName(prop), _this8.renderAttribute(prop, depth), depth, sep); | ||
}); | ||
@@ -819,13 +789,13 @@ } | ||
var refReader = self ? this.reader : this.reader.referenceReaders[reference]; | ||
var refSchema = self ? this.schematic : this.schematic.referenceSchematics[reference]; | ||
if (!refReader) { | ||
throw new SyntaxError('The reference "' + reference + '" does not exist in the "' + this.reader.name + '" schema.'); | ||
if (!refSchema) { | ||
throw new SyntaxError('The reference "' + reference + '" does not exist in the "' + this.schematic.name + '" schema.'); | ||
} | ||
if (subset && !refReader.subsets[subset]) { | ||
if (subset && !refSchema.subsets[subset]) { | ||
throw new SyntaxError('The reference "' + reference + '" does not contain a subset named "' + subset + '".'); | ||
} | ||
return this.getObjectName(refReader.name, subset, this.suffix); | ||
return this.getObjectName(refSchema.name, subset, this.suffix); | ||
} | ||
@@ -846,3 +816,3 @@ | ||
var _relations, | ||
_this10 = this; | ||
_this9 = this; | ||
@@ -855,3 +825,3 @@ var attributes /*: Definition[]*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var references = this.reader.referenceReaders; | ||
var references = this.schematic.referenceSchematics; | ||
var fields = []; | ||
@@ -871,3 +841,3 @@ var relations /*: { [key: string]: string[] }*/ = (_relations = {}, (0, _defineProperty3.default)(_relations, _Schema2.default.HAS_ONE, []), (0, _defineProperty3.default)(_relations, _Schema2.default.HAS_MANY, []), (0, _defineProperty3.default)(_relations, _Schema2.default.BELONGS_TO, []), (0, _defineProperty3.default)(_relations, _Schema2.default.BELONGS_TO_MANY, []), _relations); | ||
if (includeAttributes) { | ||
fields.push(_this10.wrapItem(_this10.formatValue(definition.attribute, 'string'), 1)); | ||
fields.push(_this9.wrapItem(_this9.formatValue(definition.attribute, 'string'), 1)); | ||
} | ||
@@ -889,2 +859,3 @@ | ||
if (relationDefinition) { | ||
/* istanbul ignore next Hard to test */ | ||
if (typeof relations[relationType] === 'undefined') { | ||
@@ -900,5 +871,5 @@ throw new Error('Invalid relation type for reference attribute "' + definition.attribute + '".'); | ||
var relationName = relationConfig.self ? _this10.reader.name : references[relationConfig.reference].name; | ||
var relationName = relationConfig.self ? _this9.schematic.name : references[relationConfig.reference].name; | ||
relations[relationConfig.relation || relationType].push(_this10.wrapProperty(relationDefinition.attribute, _this10.getObjectName(relationName, 'Schema'), 1)); | ||
relations[relationConfig.relation || relationType].push(_this9.wrapProperty(relationDefinition.attribute, _this9.getObjectName(relationName, 'Schema'), 1)); | ||
} | ||
@@ -924,3 +895,3 @@ }); | ||
if (relations[relation].length) { | ||
relationTemplate += '.' + relation + '(' + _this10.formatObject(relations[relation], 0) + ')'; | ||
relationTemplate += '.' + relation + '(' + _this9.formatObject(relations[relation], 0) + ')'; | ||
} | ||
@@ -963,3 +934,3 @@ }); | ||
return this.getObjectName(this.reader.name, reference, this.suffix); | ||
return this.getObjectName(this.schematic.name, reference, this.suffix); | ||
} | ||
@@ -966,0 +937,0 @@ |
@@ -7,2 +7,10 @@ 'use strict'; | ||
var _from = require('babel-runtime/core-js/array/from'); | ||
var _from2 = _interopRequireDefault(_from); | ||
var _set = require('babel-runtime/core-js/set'); | ||
var _set2 = _interopRequireDefault(_set); | ||
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); | ||
@@ -36,5 +44,5 @@ | ||
var _SchemaReader = require('../SchemaReader'); | ||
var _Schematic = require('../Schematic'); | ||
var _SchemaReader2 = _interopRequireDefault(_SchemaReader); | ||
var _Schematic2 = _interopRequireDefault(_Schematic); | ||
@@ -57,6 +65,2 @@ var _Definition = require('../Definition'); | ||
var _Func = require('../definitions/Func'); | ||
var _Func2 = _interopRequireDefault(_Func); | ||
var _Instance = require('../definitions/Instance'); | ||
@@ -90,6 +94,2 @@ | ||
var _isPrimitive = require('../helpers/isPrimitive'); | ||
var _isPrimitive2 = _interopRequireDefault(_isPrimitive); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -106,6 +106,6 @@ | ||
function FlowRenderer(options /*: Options*/, reader /*: SchemaReader*/) { | ||
function FlowRenderer(options /*: Options*/, schematic /*: Schematic*/) { | ||
(0, _classCallCheck3.default)(this, FlowRenderer); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (FlowRenderer.__proto__ || (0, _getPrototypeOf2.default)(FlowRenderer)).call(this, options, reader)); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (FlowRenderer.__proto__ || (0, _getPrototypeOf2.default)(FlowRenderer)).call(this, options, schematic)); | ||
@@ -148,12 +148,3 @@ _this.suffix = 'Type'; | ||
value: function renderArray(definition /*: ArrayDefinition*/, depth /*: number*/) /*: string*/ { | ||
var configType = definition.valueType.config.type; | ||
var template = this.renderAttribute(definition.valueType, depth); | ||
if ((0, _isPrimitive2.default)(configType) || configType === 'instance') { | ||
template += '[]'; | ||
} else { | ||
template = this.wrapGenerics('Array', template); | ||
} | ||
return this.wrapNullable(definition, template); | ||
return this.wrapNullable(definition, this.wrapGenerics('Array', this.renderAttribute(definition.valueType, depth))); | ||
} | ||
@@ -195,18 +186,2 @@ | ||
}, { | ||
key: 'renderFunc', | ||
value: function renderFunc(definition /*: FuncDefinition*/, depth /*: number*/) /*: string*/ { | ||
var returnType = definition.returnType ? this.renderAttribute(definition.returnType, depth + 1) : 'void'; | ||
var argTypes = definition.argTypes | ||
// eslint-disable-next-line newline-per-chained-call | ||
? this.renderObjectProps(definition.argTypes).join(' ').trim().replace(/,$/, '') : ''; | ||
return this.wrapNullable(definition, '(' + argTypes + ') => ' + returnType); | ||
} | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
}, { | ||
key: 'renderInstance', | ||
@@ -279,5 +254,7 @@ value: function renderInstance(definition /*: InstanceDefinition*/) /*: string*/ { | ||
return definition.valueTypes.map(function (item) { | ||
var set = new _set2.default(definition.valueTypes.map(function (item) { | ||
return _this3.renderAttribute(item, depth); | ||
}).join(' | '); | ||
})); | ||
return (0, _from2.default)(set.values()).join(' | '); | ||
} | ||
@@ -284,0 +261,0 @@ |
@@ -35,5 +35,5 @@ 'use strict'; | ||
var _SchemaReader = require('../SchemaReader'); | ||
var _Schematic = require('../Schematic'); | ||
var _SchemaReader2 = _interopRequireDefault(_SchemaReader); | ||
var _Schematic2 = _interopRequireDefault(_Schematic); | ||
@@ -56,6 +56,2 @@ var _Definition = require('../Definition'); | ||
var _Func = require('../definitions/Func'); | ||
var _Func2 = _interopRequireDefault(_Func); | ||
var _Instance = require('../definitions/Instance'); | ||
@@ -91,17 +87,15 @@ | ||
/** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: import type { Options } from '../types';*/ /** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: import type { Options } from '../types';*/ | ||
var ReactRenderer = function (_Renderer) { | ||
(0, _inherits3.default)(ReactRenderer, _Renderer); | ||
function ReactRenderer(options /*: Options*/, reader /*: SchemaReader*/) { | ||
function ReactRenderer(options /*: Options*/, schematic /*: Schematic*/) { | ||
(0, _classCallCheck3.default)(this, ReactRenderer); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (ReactRenderer.__proto__ || (0, _getPrototypeOf2.default)(ReactRenderer)).call(this, options, reader)); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (ReactRenderer.__proto__ || (0, _getPrototypeOf2.default)(ReactRenderer)).call(this, options, schematic)); | ||
@@ -177,12 +171,2 @@ _this.suffix = 'Shape'; | ||
}, { | ||
key: 'renderFunc', | ||
value: function renderFunc(definition /*: FuncDefinition*/, depth /*: number*/) /*: string*/ { | ||
return this.wrapPropType(definition, 'func'); | ||
} | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
}, { | ||
key: 'renderInstance', | ||
@@ -231,6 +215,6 @@ value: function renderInstance(definition /*: InstanceDefinition*/) /*: string*/ { | ||
if (self && !subset) { | ||
return '(...args) => ' + this.wrapRequired(definition, reference + '(...args)'); | ||
return '(...args) => ' + this.wrapNullable(definition, reference + '(...args)'); | ||
} | ||
return this.wrapRequired(definition, reference); | ||
return this.wrapNullable(definition, reference); | ||
} | ||
@@ -248,3 +232,3 @@ | ||
if (reference) { | ||
return this.wrapRequired(definition, reference); | ||
return this.wrapNullable(definition, reference); | ||
} | ||
@@ -286,3 +270,3 @@ | ||
value: function wrapPropType(definition /*: Definition*/, template /*: string*/) /*: string*/ { | ||
return this.wrapRequired(definition, 'PropTypes.' + template); | ||
return this.wrapNullable(definition, 'PropTypes.' + template); | ||
} | ||
@@ -299,5 +283,5 @@ | ||
}, { | ||
key: 'wrapRequired', | ||
value: function wrapRequired(definition /*: Definition*/, template /*: string*/) /*: string*/ { | ||
if (definition.isRequired && definition.isRequired()) { | ||
key: 'wrapNullable', | ||
value: function wrapNullable(definition /*: Definition*/, template /*: string*/) /*: string*/ { | ||
if (definition.isNullable && !definition.isNullable()) { | ||
return template + '.isRequired'; | ||
@@ -304,0 +288,0 @@ } |
@@ -7,2 +7,10 @@ 'use strict'; | ||
var _from = require('babel-runtime/core-js/array/from'); | ||
var _from2 = _interopRequireDefault(_from); | ||
var _set = require('babel-runtime/core-js/set'); | ||
var _set2 = _interopRequireDefault(_set); | ||
var _fromCodePoint = require('babel-runtime/core-js/string/from-code-point'); | ||
@@ -36,5 +44,5 @@ | ||
var _SchemaReader = require('../SchemaReader'); | ||
var _Schematic = require('../Schematic'); | ||
var _SchemaReader2 = _interopRequireDefault(_SchemaReader); | ||
var _Schematic2 = _interopRequireDefault(_Schematic); | ||
@@ -57,6 +65,2 @@ var _Definition = require('../Definition'); | ||
var _Func = require('../definitions/Func'); | ||
var _Func2 = _interopRequireDefault(_Func); | ||
var _Instance = require('../definitions/Instance'); | ||
@@ -100,17 +104,15 @@ | ||
/** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: import type { Options, PrimitiveType } from '../types';*/ /** | ||
* @copyright 2016, Miles Johnson | ||
* @license https://opensource.org/licenses/MIT | ||
* @flow | ||
*/ | ||
/*:: import type { Options, PrimitiveType } from '../types';*/ | ||
var TypeScriptRenderer = function (_Renderer) { | ||
(0, _inherits3.default)(TypeScriptRenderer, _Renderer); | ||
function TypeScriptRenderer(options /*: Options*/, reader /*: SchemaReader*/) { | ||
function TypeScriptRenderer(options /*: Options*/, schematic /*: Schematic*/) { | ||
(0, _classCallCheck3.default)(this, TypeScriptRenderer); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (TypeScriptRenderer.__proto__ || (0, _getPrototypeOf2.default)(TypeScriptRenderer)).call(this, options, reader)); | ||
var _this = (0, _possibleConstructorReturn3.default)(this, (TypeScriptRenderer.__proto__ || (0, _getPrototypeOf2.default)(TypeScriptRenderer)).call(this, options, schematic)); | ||
@@ -178,4 +180,3 @@ _this.suffix = 'Interface'; | ||
var members = []; | ||
var enumName = this.getObjectName(this.reader.name, definition.attribute, 'Enum'); | ||
var enumName = this.getObjectName(this.schematic.name, definition.attribute, 'Enum'); | ||
var currentIndex = 0; | ||
@@ -187,2 +188,3 @@ var currentChar = 65; | ||
// Assign values incrementally starting from 0 | ||
default: | ||
case 'string': | ||
@@ -204,5 +206,2 @@ values.forEach(function (value /*: PrimitiveType*/) { | ||
break; | ||
default: | ||
break; | ||
} | ||
@@ -220,18 +219,2 @@ | ||
}, { | ||
key: 'renderFunc', | ||
value: function renderFunc(definition /*: FuncDefinition*/, depth /*: number*/) /*: string*/ { | ||
var returnType = definition.returnType ? this.renderAttribute(definition.returnType, depth + 1) : 'void'; | ||
var argTypes = definition.argTypes | ||
// eslint-disable-next-line newline-per-chained-call | ||
? this.renderObjectProps(definition.argTypes).join(' ').replace(/,$/, '') : ''; | ||
return '(' + argTypes + ') => ' + returnType; | ||
} | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
}, { | ||
key: 'renderInstance', | ||
@@ -294,28 +277,8 @@ value: function renderInstance(definition /*: InstanceDefinition*/) /*: string*/ { | ||
return definition.valueTypes.map(function (item /*: Definition*/) { | ||
var value = _this2.renderAttribute(item, depth); | ||
var set = new _set2.default(definition.valueTypes.map(function (item) { | ||
return _this2.renderAttribute(item, depth); | ||
})); | ||
// Functions need to be wrapped in parenthesis when used in unions | ||
return item instanceof _Func2.default ? '(' + value + ')' : value; | ||
}).join(' | '); | ||
return (0, _from2.default)(set.values()).join(' | '); | ||
} | ||
/** | ||
* Mark as optional. | ||
* | ||
* @param {Definition} definition | ||
* @returns {String} | ||
*/ | ||
}, { | ||
key: 'wrapPropertyName', | ||
value: function wrapPropertyName(definition /*: Definition*/) /*: string*/ { | ||
var template = definition.attribute; | ||
if (!definition.isRequired()) { | ||
return template + '?'; | ||
} | ||
return template; | ||
} | ||
}]); | ||
@@ -322,0 +285,0 @@ return TypeScriptRenderer; |
@@ -47,10 +47,18 @@ 'use strict'; | ||
var _Factory = require('./Factory'); | ||
var _RendererFactory = require('./RendererFactory'); | ||
var _Factory2 = _interopRequireDefault(_Factory); | ||
var _RendererFactory2 = _interopRequireDefault(_RendererFactory); | ||
var _SchemaReader = require('./SchemaReader'); | ||
var _Schematic = require('./Schematic'); | ||
var _SchemaReader2 = _interopRequireDefault(_SchemaReader); | ||
var _Schematic2 = _interopRequireDefault(_Schematic); | ||
var _node = require('./readers/node'); | ||
var _node2 = _interopRequireDefault(_node); | ||
var _graphql = require('./readers/graphql'); | ||
var _graphql2 = _interopRequireDefault(_graphql); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -67,3 +75,3 @@ | ||
/*:: type ResolveList = { | ||
parentReader?: SchemaReader, | ||
parentSchematic?: Schematic, | ||
refKey?: string, | ||
@@ -81,6 +89,7 @@ resolvePath: string, | ||
/** | ||
* Output the rendered reader to stdout. | ||
* Output the rendered schema to stdout. | ||
* | ||
* @param {String} value | ||
*/ | ||
/* istanbul ignore next */ | ||
@@ -93,3 +102,3 @@ | ||
/** | ||
* Transpile either a file or a folder by rendering each reader file. | ||
* Transpile either a file or a folder by rendering each schematic file. | ||
* | ||
@@ -99,2 +108,3 @@ * @param {String} target | ||
*/ | ||
/* istanbul ignore next */ | ||
value: function transpile(target /*: string*/) /*: Promise<string>*/ { | ||
@@ -138,15 +148,13 @@ var _this = this; | ||
var filePaths = _fs2.default.readdirSync(folderPath); | ||
var readers = []; | ||
var schematics = []; | ||
filePaths.forEach(function (filePath /*: string*/) { | ||
if (filePath.match(/\.(js|json)$/)) { | ||
readers = [].concat((0, _toConsumableArray3.default)(readers), (0, _toConsumableArray3.default)(_this2.extractReaders(_path2.default.join(folderPath, filePath)))); | ||
} | ||
schematics = [].concat((0, _toConsumableArray3.default)(schematics), (0, _toConsumableArray3.default)(_this2.extractSchematics(_path2.default.join(folderPath, filePath)))); | ||
}); | ||
return this.generateOutput(readers); | ||
return this.generateOutput(schematics); | ||
} | ||
/** | ||
* Transpile a file by rendering the reader at the defined path. | ||
* Transpile a file by rendering the schematic at the defined path. | ||
* | ||
@@ -160,15 +168,15 @@ * @param {String} file | ||
value: function transpileFile(file /*: string*/) /*: string*/ { | ||
return this.generateOutput(this.extractReaders(file)); | ||
return this.generateOutput(this.extractSchematics(file)); | ||
} | ||
/** | ||
* Extract a list of file paths based on references defined within the reader. | ||
* Extract a list of file paths based on references defined within the schematic. | ||
* | ||
* @param {String} filePath | ||
* @returns {SchemaReader[]} | ||
* @returns {Schematic[]} | ||
*/ | ||
}, { | ||
key: 'extractReaders', | ||
value: function extractReaders(filePath /*: string*/) /*: SchemaReader[]*/ { | ||
key: 'extractSchematics', | ||
value: function extractSchematics(filePath /*: string*/) /*: Schematic[]*/ { | ||
var _this3 = this; | ||
@@ -178,3 +186,3 @@ | ||
var toResolve /*: ResolveList[]*/ = [{ resolvePath: filePath }]; | ||
var readers = []; | ||
var schematics = []; | ||
@@ -186,9 +194,14 @@ // Use `require()` as it handles JSON and JS files easily | ||
resolvePath = _toResolve$shift.resolvePath, | ||
parentReader = _toResolve$shift.parentReader, | ||
parentSchematic = _toResolve$shift.parentSchematic, | ||
refKey = _toResolve$shift.refKey; | ||
// Only support JS and JSON | ||
var pathExt = _path2.default.extname(resolvePath); | ||
var data = null; | ||
if (!resolvePath.match(/\.(js|json)$/)) { | ||
/* istanbul ignore else */ | ||
if (pathExt === '.js' || pathExt === '.json') { | ||
data = (0, _node2.default)(resolvePath); | ||
} else if (pathExt === '.gql' || pathExt === '.graphql') { | ||
data = (0, _graphql2.default)(resolvePath); | ||
} else { | ||
// eslint-disable-next-line no-continue | ||
@@ -198,19 +211,16 @@ return 'continue'; | ||
/* eslint-disable */ | ||
// $FlowIssue `resolvePath` cannot be a literal string | ||
var reader = new _SchemaReader2.default(resolvePath, require(resolvePath), _this3.options); | ||
/* eslint-enable */ | ||
var schematic = new _Schematic2.default(resolvePath, data, _this3.options); | ||
readers.unshift(reader); | ||
schematics.unshift(schematic); | ||
// Assign to parent | ||
if (parentReader && refKey) { | ||
parentReader.referenceReaders[refKey] = reader; | ||
if (parentSchematic && refKey) { | ||
parentSchematic.referenceSchematics[refKey] = schematic; | ||
} | ||
// Extract child references | ||
(0, _keys2.default)(reader.references).forEach(function (ref /*: string*/) { | ||
(0, _keys2.default)(schematic.references).forEach(function (ref /*: string*/) { | ||
toResolve.push({ | ||
resolvePath: _path2.default.normalize(_path2.default.join(basePath, reader.references[ref])), | ||
parentReader: reader, | ||
resolvePath: _path2.default.normalize(_path2.default.join(basePath, schematic.references[ref])), | ||
parentSchematic: schematic, | ||
refKey: ref | ||
@@ -227,9 +237,9 @@ }); | ||
return readers; | ||
return schematics; | ||
} | ||
/** | ||
* Generate the output by combining all readers into a single output. | ||
* Generate the output by combining all schematics into a single output. | ||
* | ||
* @param {SchemaReader[]} readers | ||
* @param {Schematic[]} schematics | ||
* @returns {String} | ||
@@ -240,3 +250,3 @@ */ | ||
key: 'generateOutput', | ||
value: function generateOutput(readers /*: SchemaReader[]*/) /*: string*/ { | ||
value: function generateOutput(schematics /*: Schematic[]*/) /*: string*/ { | ||
var _this4 = this; | ||
@@ -253,8 +263,8 @@ | ||
// Wrap in a set to remove duplicates | ||
readers.forEach(function (reader /*: SchemaReader*/) { | ||
if (rendered.has(reader.path)) { | ||
schematics.forEach(function (schematic /*: Schematic*/) { | ||
if (rendered.has(schematic.path)) { | ||
return; | ||
} | ||
var renderer = _Factory2.default.renderer(_this4.options, reader); | ||
var renderer = _RendererFactory2.default.factory(_this4.options, schematic); | ||
@@ -275,3 +285,3 @@ renderer.parse(); | ||
rendered.add(reader.path); | ||
rendered.add(schematic.path); | ||
}); | ||
@@ -305,2 +315,3 @@ | ||
*/ | ||
/* istanbul ignore next */ | ||
@@ -307,0 +318,0 @@ }, { |
@@ -12,4 +12,3 @@ "use strict"; | ||
/*:: export type Options = { | ||
defaultNull: boolean, | ||
defaultRequired: boolean, | ||
defaultNullable: boolean, | ||
includeAttributes: boolean, | ||
@@ -27,9 +26,7 @@ includeSchemas: boolean, | ||
/*:: export type BaseConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
};*/ | ||
/*:: export type ArrayConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
@@ -39,9 +36,7 @@ valueType: TypeDefinition, | ||
/*:: export type BoolConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
};*/ | ||
/*:: export type EnumConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
@@ -51,18 +46,9 @@ values: PrimitiveType[], | ||
};*/ | ||
/*:: export type FuncConfig = { | ||
argTypes?: TypeDefinition[], | ||
null?: boolean, | ||
required?: boolean, | ||
returnType?: TypeDefinition, | ||
type: string, | ||
};*/ | ||
/*:: export type InstanceConfig = { | ||
contract: string, | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
};*/ | ||
/*:: export type NumberConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
@@ -72,4 +58,3 @@ };*/ | ||
keyType: TypeDefinition, | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
@@ -80,6 +65,5 @@ valueType: TypeDefinition, | ||
export?: boolean, | ||
null?: boolean, | ||
nullable?: boolean, | ||
reference: string, | ||
relation?: string, | ||
required?: boolean, | ||
self: boolean, | ||
@@ -91,15 +75,12 @@ subset?: string, | ||
attributes: { [key: string]: TypeDefinition }, | ||
null?: boolean, | ||
nullable?: boolean, | ||
reference?: string, | ||
required?: boolean, | ||
type: string, | ||
};*/ | ||
/*:: export type StringConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
};*/ | ||
/*:: export type UnionConfig = { | ||
null?: boolean, | ||
required?: boolean, | ||
nullable?: boolean, | ||
type: string, | ||
@@ -113,3 +94,3 @@ valueTypes: TypeDefinition[], | ||
/*:: export type TypeDefinition = string | | ||
ArrayConfig | BoolConfig | EnumConfig | FuncConfig | InstanceConfig | NumberConfig | | ||
ArrayConfig | BoolConfig | EnumConfig | InstanceConfig | NumberConfig | | ||
ObjectConfig | ReferenceConfig | ShapeConfig | StringConfig | UnionConfig;*/ | ||
@@ -134,4 +115,3 @@ /*:: export type MetadataField = { | ||
attributes: string[], | ||
null?: { [key: string]: boolean }, | ||
required?: { [key: string]: boolean }, | ||
nullable?: { [key: string]: boolean }, | ||
};*/ | ||
@@ -138,0 +118,0 @@ /*:: export type SubsetsField = { [key: string]: string[] | SubsetStructure };*/ |
{ | ||
"name": "shapeshifter", | ||
"version": "2.3.0", | ||
"description": "Generate relational schemas, React prop types, Flow type aliases, or TypeScript interfaces from JSON schema files.", | ||
"version": "3.0.0", | ||
"description": "Generate relational schemas, React prop types, Flow type aliases, or TypeScript interfaces from JSON or GraphQL schematic files.", | ||
"keywords": [ | ||
"generate", | ||
"schema", | ||
"schematic", | ||
"react", | ||
@@ -21,3 +22,4 @@ "prop", | ||
"transpile", | ||
"entity" | ||
"entity", | ||
"graphql" | ||
], | ||
@@ -33,14 +35,13 @@ "main": "./lib/index.js", | ||
"clean": "rimraf ./lib", | ||
"build": "babel ./src -d ./lib && yarn run build:flow", | ||
"build:flow": "cp ./flow/shapeshifter.js.flow ./lib", | ||
"watch": "babel --watch ./src -d ./lib", | ||
"build": "babel ./src -d ./lib && cp ./flow/shapeshifter.js.flow ./lib", | ||
"lint": "eslint ./src ./tests", | ||
"check": "yarn run check:flow && yarn run check:typescript", | ||
"check:flow": "flow check", | ||
"check:typescript": "tsc --noEmit --allowJs ./tests/expected/typescript/*", | ||
"mocha": "mocha --opts ./mocha.opts './tests/**/*.test.js'", | ||
"pretest": "yarn run clean && yarn run build", | ||
"test": "yarn run mocha", | ||
"posttest": "yarn run lint && yarn run check", | ||
"preversion": "yarn test" | ||
"check:typescript": "tsc --noEmit --allowJs ./tests/expected/gql/typescript/* ./tests/expected/node/typescript/*", | ||
"jest": "jest --config ./jest.json", | ||
"coverage": "yarn run jest -- --coverage", | ||
"pretest": "yarn run lint", | ||
"test": "yarn run jest", | ||
"posttest": "yarn run check", | ||
"preversion": "yarn test && yarn run clean && yarn run build" | ||
}, | ||
@@ -69,21 +70,21 @@ "repository": { | ||
"babel-eslint": "^7.1.1", | ||
"babel-jest": "^18.0.0", | ||
"babel-plugin-transform-flow-comments": "^6.17.0", | ||
"babel-plugin-transform-runtime": "^6.15.0", | ||
"babel-preset-es2015": "^6.18.0", | ||
"babel-preset-latest": "^6.16.0", | ||
"babel-preset-stage-2": "^6.18.0", | ||
"babel-register": "^6.18.0", | ||
"chai": "^3.5.0", | ||
"chai-files": "^1.4.0", | ||
"eslint": "^3.12.1", | ||
"eslint-config-airbnb": "^13.0.0", | ||
"eslint-plugin-flowtype": "^2.25.0", | ||
"eslint": "^3.13.1", | ||
"eslint-config-airbnb": "^14.0.0", | ||
"eslint-plugin-flowtype": "^2.29.2", | ||
"eslint-plugin-import": "^2.2.0", | ||
"eslint-plugin-jsx-a11y": "^2.2.3", | ||
"eslint-plugin-react": "^6.7.1", | ||
"flow-bin": "^0.37.0", | ||
"mocha": "^3.1.2", | ||
"react": "^15.4.0", | ||
"eslint-plugin-jsx-a11y": "^3.0.2", | ||
"eslint-plugin-react": "^6.9.0", | ||
"flow-bin": "^0.37.4", | ||
"graphql": "^0.8.2", | ||
"jest": "^18.1.0", | ||
"react": "^15.4.2", | ||
"rimraf": "^2.5.4", | ||
"typescript": "^2.1.4" | ||
"typescript": "^2.1.5" | ||
} | ||
} |
318
README.md
@@ -1,2 +0,2 @@ | ||
# Shapeshifter v2.3.0 | ||
# Shapeshifter v3.0.0 | ||
[](https://travis-ci.org/milesj/shapeshifter) | ||
@@ -6,7 +6,7 @@ | ||
files that export React prop types, Flow type aliases, or TypeScript | ||
interfaces, as well as relation schema classes from JSON schema files. | ||
Schemas can represent database tables, API endpoints, data structures, | ||
resources, internal shapes, and more. | ||
interfaces, as well as relation schema classes from JSON or GraphQL | ||
schematic files. Schematics can represent database tables, API endpoints, | ||
data structures, resources, internal shapes, and more. | ||
Take this user schema for example. | ||
Take this user schematic for example. | ||
@@ -21,3 +21,3 @@ ```json | ||
"type": "string", | ||
"required": true | ||
"nullable": true | ||
}, | ||
@@ -41,9 +41,9 @@ "location": { | ||
export const UserShape = PropTypes.shape({ | ||
id: PropTypes.number, | ||
username: PropTypes.string, | ||
email: PropTypes.string.isRequired, | ||
id: PropTypes.number.isRequired, | ||
username: PropTypes.string.isRequired, | ||
email: PropTypes.string, | ||
location: PropTypes.shape({ | ||
lat: PropTypes.number, | ||
long: PropTypes.number, | ||
}), | ||
lat: PropTypes.number.isRequired, | ||
long: PropTypes.number.isRequired, | ||
}).isRequired, | ||
}); | ||
@@ -60,3 +60,3 @@ ``` | ||
username: string, | ||
email: string, | ||
email: ?string, | ||
location: { | ||
@@ -73,8 +73,8 @@ lat: number, | ||
export interface UserInterface { | ||
id?: number; | ||
username?: string; | ||
id: number; | ||
username: string; | ||
email: string; | ||
location?: { | ||
lat?: number; | ||
long?: number; | ||
location: { | ||
lat: number; | ||
long: number; | ||
}; | ||
@@ -94,3 +94,3 @@ } | ||
* Node 4+ | ||
* React 0.14+ / Flow 0.20+ / TypeScript 1.6+ | ||
* React 0.14+ / Flow 0.30+ / TypeScript 2.0+ | ||
@@ -108,4 +108,3 @@ ## Installation | ||
If you're generating schema classes, it will need to be a normal | ||
dependency. | ||
If you're generating schema classes, it will need to be a normal dependency. | ||
@@ -126,4 +125,4 @@ ``` | ||
The binary input accepts either a single schema file or a directory of | ||
schema files. If a directory is provided, they will be combined into | ||
The binary input accepts either a single schematic file or a directory of | ||
schematic files. If a directory is provided, they will be combined into | ||
a single output. | ||
@@ -138,27 +137,18 @@ | ||
* `--help`, `-h` - Displays a help menu. | ||
* `--nullable`, `-n` - Marks all attributes as nullable by default. | ||
Defaults to false. (Flow only) | ||
* `--required`, `-r` - Marks all attributes as required by default. | ||
Defaults to false. (React and TypeScript only) | ||
Not applicable to GraphQL. Defaults to false. | ||
* `--indent` - Defines the indentation characters to use in the | ||
generated output. Defaults to 2 spaces. | ||
generated output. Defaults to 2 spaces. | ||
* `--format` - The format to output to. Accepts "react", "flow", or | ||
"typescript". Defaults to "react". | ||
"typescript". Defaults to "react". | ||
* `--schemas` - Include schema class exports in the output. Defaults to | ||
"false". | ||
"false". | ||
* `--attributes` - Include an attribute list in the schema class export. | ||
Defaults to "false". | ||
Defaults to "false". | ||
* `--types` - Include type definition exports in the output. Defaults to | ||
"false". | ||
"false". | ||
## Documentation | ||
* [JSON Structure](#json-structure) | ||
* [Schematic Structure](#schematic-structure) | ||
* [Attributes](#attributes) | ||
@@ -169,2 +159,3 @@ * [Metadata](#metadata) | ||
* [Subsets](#subsets) | ||
* [GraphQL Support](#graphql-support) | ||
* [Attribute Types](#attribute-types) | ||
@@ -187,23 +178,35 @@ * [Primitives](#primitives) | ||
### JSON Structure | ||
### Schematic Structure | ||
A schema can either be a JSON file, or a JavaScript file | ||
that exports an object (Node.js compatible). JSON is preferred | ||
as it's a consumable format across many languages. | ||
Shapeshifter is powered by files known as schematics, which can | ||
be a JSON (`.json`), JavaScript (`.js`), or GraphQL file (`.gql`). | ||
Schematics must define a name, used to denote the name of the | ||
ES2015 export, and set of attributes, used as as fields in which | ||
the schematic is defining. | ||
Every schema requires a `name` and `attributes` property. | ||
The name denotes the name of the export prefix found in the | ||
ES2015 transpiled output file, while the attributes denotes the | ||
available fields in the current schema. | ||
```json | ||
{ | ||
"name": "Users", | ||
"attributes": {} | ||
"name": "User", | ||
"attributes": { | ||
"id": "number" | ||
} | ||
} | ||
``` | ||
```javascript | ||
module.exports = { | ||
name: 'User', | ||
attributes: { | ||
id: 'number' | ||
} | ||
}; | ||
``` | ||
```graphql | ||
type User { | ||
id: ID | ||
} | ||
``` | ||
Furthermore, a schema supports the following optional properties: | ||
`meta`, `imports`, `constants`, `references`, and `subsets`. Continue | ||
reading for more information on all the supported schema properties. | ||
> GraphQL has limited functionality compared to JSON or JavaScript. | ||
> Jump to the section on [GraphQL](#graphql-support), and read the | ||
> documentation thoroughly, for more information. | ||
@@ -234,21 +237,28 @@ #### Attributes | ||
##### Modifiers | ||
> For GraphQL, attributes are analogous to [fields](https://facebook.github.io/graphql/#sec-Language.Fields). | ||
All attribute type definitions support two modifier properties, | ||
`required` and `null`. Both of these values accept a boolean value. | ||
##### Nullable | ||
When `required` is used by React, it will append `isRequired` to all | ||
prop types. When used by TypeScript, it will omit `?` on every | ||
property name. Required attributes are not supported by Flow, | ||
instead it supports `null`. Nullable fields will prepend `?` to | ||
every type alias. | ||
All attribute type definitions support the `nullable` modifier, | ||
which accepts a boolean value, and triggers the following: | ||
* React: Non-nullable fields will append `isRequired` to the prop type. | ||
* Flowtype: Nullable fields will prepend `?` to each type alias. | ||
* TypeScript: Does nothing, please use `--strictNullChecks` provided | ||
by TypeScript. | ||
```json | ||
"field": { | ||
"type": "string", | ||
"required": true, | ||
"null": false | ||
"nullable": false | ||
} | ||
``` | ||
If using GraphQL, all attributes are nullable by default. To mark a field | ||
as non-nullable, append an exclamation mark (`!`) to the type. | ||
```graphql | ||
field: String! | ||
``` | ||
#### Metadata | ||
@@ -271,2 +281,10 @@ | ||
If using GraphQL, the `ID` type can be used to denote a primary key. | ||
```graphql | ||
type User { | ||
id: ID | ||
} | ||
``` | ||
#### Imports | ||
@@ -290,2 +308,4 @@ | ||
> Imports are not supported by GraphQL. | ||
#### Constants | ||
@@ -310,2 +330,4 @@ | ||
> Constants are not supported by GraphQL. | ||
#### Subsets | ||
@@ -317,7 +339,6 @@ | ||
property can either be an array of [attribute names](#attributes), | ||
or an object of `attributes`, `required` (optional), and `null` | ||
(optional) properties. | ||
or an object of `attributes` and `nullable` (optional) properties. | ||
Unlike `required` and `null` properties found on type definitions, | ||
these properties represent a mapping of attributes in the current | ||
Unlike `nullable` properties found on type definitions, | ||
this property represents a mapping of attributes in the current | ||
subset to boolean values, which enable or disable the modifier. | ||
@@ -329,13 +350,6 @@ | ||
"SetB": { | ||
"attributes": ["foo", "qux"], | ||
"null": { | ||
"attributes": ["foo", "baz"], | ||
"nullable": { | ||
"foo": true | ||
} | ||
}, | ||
"SetC": { | ||
"attributes": ["bar", "baz"], | ||
"required": { | ||
"bar": true, | ||
"baz": false | ||
} | ||
} | ||
@@ -348,7 +362,3 @@ }, | ||
"type": "string", | ||
"required": true | ||
}, | ||
"qux": { | ||
"type": "string", | ||
"null": true | ||
"nullable": true | ||
} | ||
@@ -358,5 +368,23 @@ } | ||
> Subsets are not supported by GraphQL. | ||
### GraphQL Support | ||
Shapeshifter supports reading from GraphQL (`.gql`) type files -- if you | ||
prefer GraphQL over JavaScript/JSON. However, since GraphQL is a rather strict | ||
and direct representation of a data model, only a small subset of Shapeshifter | ||
functionality is available. | ||
When defining a GraphQL schematic, multiple definitions (`type`, `enum`, `union`, etc) | ||
can exist in a single schematic, with the last `type` definition being | ||
used as the schematic representation. All prior definitions will be used | ||
as internal shapes, references, enums, and unions. | ||
For more guidance, [take a look at our test cases.](./tests/schemas/gql/) | ||
> Introspection support being looked into! | ||
### Attribute Types | ||
For every attribute defined in a JSON schema, a type definition is required. | ||
For every attribute defined in a schematic, a type definition is required. | ||
Types will be generated when the `--types` CLI option is passed. The | ||
@@ -376,2 +404,7 @@ following types are supported. | ||
``` | ||
```graphql | ||
name: String | ||
status: Int | ||
active: Boolean | ||
``` | ||
@@ -406,5 +439,5 @@ As well as the expanded standard notation. | ||
// TypeScript | ||
name?: string; | ||
status?: number; | ||
active?: boolean; | ||
name: string; | ||
status: number; | ||
active: boolean; | ||
``` | ||
@@ -427,2 +460,5 @@ | ||
``` | ||
```graphql | ||
messages: [String] | ||
``` | ||
@@ -439,3 +475,3 @@ This transpiles down to: | ||
// TypeScript | ||
messages?: string[]; | ||
messages: string[]; | ||
``` | ||
@@ -473,3 +509,3 @@ | ||
// TypeScript | ||
costs?: { [key: string]: number }; | ||
costs: { [key: string]: number }; | ||
``` | ||
@@ -479,2 +515,4 @@ | ||
> Objects are not supported by GraphQL. Use shapes instead. | ||
#### Enums | ||
@@ -493,3 +531,12 @@ | ||
``` | ||
```graphql | ||
enum WordsEnum { | ||
FOO | ||
BAR | ||
BAZ | ||
} | ||
words: WordsEnum | ||
``` | ||
This transpiles down to: | ||
@@ -511,5 +558,7 @@ | ||
words?: SchemaWordsEnum; | ||
words: SchemaWordsEnum; | ||
``` | ||
> Transpilation output slightly differs when using GraphQL. | ||
#### Shapes | ||
@@ -520,3 +569,3 @@ | ||
type for all keys and values, while a shape defines individual | ||
attributes. This provides nested structures within a schema. | ||
attributes. This provides nested structures within a schematic. | ||
@@ -533,3 +582,3 @@ A shape is similar to a struct found in the C language. | ||
"type": "string", | ||
"required": true | ||
"nullable": true | ||
} | ||
@@ -539,3 +588,12 @@ } | ||
``` | ||
```graphql | ||
type LocationStruct { | ||
lat: Number | ||
long: Number | ||
name: String! | ||
} | ||
location: LocationStruct | ||
``` | ||
This transpiles to: | ||
@@ -546,5 +604,5 @@ | ||
location: PropTypes.shape({ | ||
lat: PropTypes.number, | ||
long: PropTypes.number, | ||
name: PropTypes.string.isRequired, | ||
lat: PropTypes.number.isRequired, | ||
long: PropTypes.number.isRequired, | ||
name: PropTypes.string, | ||
}), | ||
@@ -556,9 +614,9 @@ | ||
long: number, | ||
name: string, | ||
name: ?string, | ||
}, | ||
// TypeScript | ||
location?: { | ||
lat?: number, | ||
long?: number, | ||
location: { | ||
lat: number, | ||
long: number, | ||
name: string, | ||
@@ -573,3 +631,3 @@ }, | ||
Shapes are powerful at defining nested attributes, while | ||
[references](#references) are great at reusing external schemas. | ||
[references](#references) are great at reusing external schematics. | ||
Shape references are a combination of both of these patterns -- | ||
@@ -619,2 +677,5 @@ it permits a local shape definition to be used throughout | ||
> If an additional `type` definition exists within a GraphQL schematic, | ||
> it will be treated as a shape reference, otherwise, a normal reference. | ||
#### Unions | ||
@@ -639,3 +700,8 @@ | ||
``` | ||
```graphql | ||
union PrimitiveUnion = String | Int | ||
error: PrimitiveUnion | ||
``` | ||
This transpiles to: | ||
@@ -655,3 +721,3 @@ | ||
// TypeScript | ||
error?: string | number | Error; | ||
error: string | number | Error; | ||
``` | ||
@@ -662,15 +728,15 @@ | ||
The final type, `reference`, is the most powerful and versatile type. | ||
A reference provides a link to an external schema file, permitting | ||
easy re-use and extensibility, while avoiding schema structure | ||
A reference provides a link to an external schematic file, permitting | ||
easy re-use and extensibility, while avoiding schematic structure | ||
duplication across files. | ||
To make use of references, a `references` map must be defined in | ||
the root of the schema. Each value in the map is a relative path to | ||
an external schema file. | ||
the root of the schematic. Each value in the map is a relative path to | ||
an external schematic file. | ||
```json | ||
{ | ||
"name": "Users", | ||
"name": "User", | ||
"references": { | ||
"Profile": "./profile.json" | ||
"Profile": "./Profile.json" | ||
}, | ||
@@ -684,3 +750,3 @@ "attributes": {} | ||
the references map. An optional `subset` property can be defined | ||
that points to a subset found in the reference schema file. | ||
that points to a subset found in the reference schematic file. | ||
@@ -694,2 +760,5 @@ ```json | ||
``` | ||
```graphql | ||
profile: Profile | ||
``` | ||
@@ -706,3 +775,3 @@ This transpiles to: | ||
// TypeScript | ||
profile?: ProfileInterface; | ||
profile: ProfileInterface; | ||
``` | ||
@@ -712,6 +781,10 @@ | ||
> If a `type` definition does not exist in a GraphQL schematic, | ||
> Shapeshifter will assume it to be a reference to a relative file of the same name. | ||
> For example, using the code block mentioned previously, `./Profile.gql`. | ||
##### Self References | ||
It's possible to create recursive structures using the `self` | ||
property, which refers to the current schema in which it was defined. | ||
property, which refers to the current schematic in which it was defined. | ||
When using self, the `reference` property and the `references` map | ||
@@ -726,2 +799,7 @@ is not required. | ||
``` | ||
```graphql | ||
type Schema { | ||
node: Schema | ||
} | ||
``` | ||
@@ -731,3 +809,3 @@ ##### Exported Schemas | ||
When generating schema classes using the `--schemas` CLI option, | ||
all references defined in a schema are considered a relation (ORM style), | ||
all references defined in a schematic are considered a relation (ORM style), | ||
and in turn, will generate schemas as well. To disable this export | ||
@@ -744,2 +822,4 @@ from occurring, set `export` to false. | ||
> Disabling exports are not supported by GraphQL. | ||
##### Relation Type | ||
@@ -763,2 +843,4 @@ | ||
> Customizing the relation type is not supported by GraphQL. | ||
#### Instance Ofs | ||
@@ -807,4 +889,6 @@ | ||
#### Schema Classes | ||
> Instance Ofs are not supported by GraphQL. | ||
### Schema Classes | ||
Schema classes are ES2015 based classes that are generated and included | ||
@@ -826,7 +910,7 @@ in the output when `--schemas` is passed to the command line. These | ||
the first argument to the constructor. This field is based on | ||
`meta.resourceName` in the JSON schema file. | ||
`meta.resourceName` in the schematic file. | ||
* `primaryKey` (string) - The name of the primary key in the current | ||
schema, passed as the second argument to the constructor. This field | ||
is based on `meta.primaryKey` in the JSON schema file. Defaults to "id". | ||
is based on `meta.primaryKey` in the JSON schematic file. Defaults to "id". | ||
@@ -852,4 +936,6 @@ * `attributes` (string[]) - List of attribute names in the current schema. | ||
##### Including Attributes | ||
> Schemas are not supported by GraphQL. | ||
#### Including Attributes | ||
By default, attributes are excluded from the output unless the | ||
@@ -868,3 +954,3 @@ `--attributes` CLI option is passed. Once passed, they are defined | ||
##### Including Relations | ||
#### Including Relations | ||
@@ -915,5 +1001,1 @@ Unlike attributes, relations are always included in the output, as | ||
map to database tables or data structures very well, if at all. | ||
The same could be said for `func` -- however, that is supported. | ||
I've simply opted out in mentioning it in the documentation, as I'm | ||
not too sure on its use case. Kind of a hidden feature really. |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
159234
37
3323
952
3