diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..30884b3 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,24 @@ +name: Node.js + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x, 10.x, 12.x, 13.x, 14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm run build --if-present + - run: npm test + env: + CI: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f864a2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js - -node_js: -- "13" -- "12 -- "10" -- "8" diff --git a/src/ObjectSchema.js b/src/ObjectSchema.js index 44c3416..db012b1 100644 --- a/src/ObjectSchema.js +++ b/src/ObjectSchema.js @@ -267,8 +267,14 @@ const ObjectSchema = ({ schema = initialState, ...options } = {}) => { } const src = base._getState() const extended = merge(src, schema, { arrayMerge: combineMerge }) - const { valueOf, ...rest } = BaseSchema({ schema: extended, ...options }) - return { valueOf } + const { + valueOf, + isFluentSchema, + FLUENT_SCHEMA, + _getState, + ...rest + } = BaseSchema({ schema: extended, ...options }) + return { valueOf, isFluentSchema, FLUENT_SCHEMA, _getState } }, /** diff --git a/src/ObjectSchema.test.js b/src/ObjectSchema.test.js index cdcf7ed..753b71f 100644 --- a/src/ObjectSchema.test.js +++ b/src/ObjectSchema.test.js @@ -600,12 +600,17 @@ describe('ObjectSchema', () => { .id('base') .title('base') .additionalProperties(false) - .prop('foo', S.string().minLength(5)) + .prop( + 'foo', + S.string() + .minLength(5) + .required(true) + ) const extended = S.object() .id('extended') .title('extended') - .prop('bar', S.number()) + .prop('bar', S.string().required()) .extend(base) expect(extended.valueOf()).toEqual({ $schema: 'http://json-schema.org/draft-07/schema#', @@ -618,12 +623,14 @@ describe('ObjectSchema', () => { minLength: 5, }, bar: { - type: 'number', + type: 'string', }, }, + required: ['foo', 'bar'], type: 'object', }) }) + it('extends a nested schema', () => { const base = S.object() .id('base') @@ -743,6 +750,29 @@ describe('ObjectSchema', () => { }, }) }) + it('extends a chain of schemas overriding the props', () => { + const base = S.object().prop('reason', S.string().title('title')) + + const extended = S.object() + .prop('other') + .prop('reason', S.string().minLength(1)) + .extend(base) + + const extendedAgain = S.object() + .prop('again') + .prop('reason', S.string().minLength(2)) + .extend(extended) + + expect(extendedAgain.valueOf()).toEqual({ + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + other: {}, + again: {}, + reason: { title: 'title', type: 'string', minLength: 2 }, + }, + }) + }) it('throws an error if a schema is not provided', () => { expect(() => { diff --git a/src/utils.js b/src/utils.js index 71d41e2..cbcf052 100644 --- a/src/utils.js +++ b/src/utils.js @@ -40,10 +40,10 @@ const combineMerge = (target, source, options) => { const destination = target.slice() source.forEach((item, index) => { - const prop = target.find(prop => prop.name === item.name) + const prop = target.find(attr => attr.name === item.name) if (typeof destination[index] === 'undefined') { destination[index] = options.cloneUnlessOtherwiseSpecified(item, options) - } else if (prop) { + } else if (options.isMergeableObject(prop)) { const propIndex = target.findIndex(prop => prop.name === item.name) destination[propIndex] = merge(prop, item, options) } else if (target.indexOf(item) === -1) {