Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Commit

Permalink
feat(project): add serializeSync method (#549)
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksmms authored Sep 2, 2020
1 parent f7c9131 commit e2a8c75
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 22 deletions.
6 changes: 6 additions & 0 deletions packages/apib-serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# API Elements: API Blueprint Serializer Changelog

## 0.16.2 (2020-08-31)

### Enhancements

- Enable synchronous serialization.

## 0.16.1 (2020-08-06)

Adds compatibility for @apielements/core 0.2.0.
Expand Down
21 changes: 20 additions & 1 deletion packages/apib-serializer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,33 @@ $ npm install @apielements/apib-serializer

## Usage

### Async

```js
import fury from 'fury';
import apibSerializer from '@apielements/apib-serializer';

fury.use(apibSerializer);

// Assume `api` is a Minim element instance, e.g. from `fury.parse(...)`
fury.serialize({api}, (err, content) => {
fury.serialize({ api }, (err, content) => {
fs.write('serialized.apib', content, 'utf8');
});
```

### Sync

```js
import fury from 'fury';
import apibSerializer from '@apielements/apib-serializer';

fury.use(apibSerializer);

try {
// Assume `api` is a Minim element instance, e.g. from `fury.parse(...)`
const content = fury.serializeSync({ api });
fs.write('serialized.apib', content, 'utf8');
} catch (error) {
console.log(error);
}
```
20 changes: 16 additions & 4 deletions packages/apib-serializer/lib/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,30 @@ const mediaTypes = [
/*
* Serialize an API into API Blueprint.
*/
function filterExtraSpacing(apib) {
const result = apib.trim().replace(/\n\s*\n\s*\n/g, '\n\n');

return `${result}\n`;
}

function serialize({ api }) {
return new Promise((resolve, reject) => {
nunjucks.render('template.nunjucks', { api }, (err, apib) => {
if (err) {
return reject(err);
}

// Attempt to filter out extra spacing
const result = apib.trim().replace(/\n\s*\n\s*\n/g, '\n\n');
return resolve(`${result}\n`);
return resolve(filterExtraSpacing(apib));
});
});
}

module.exports = { name, mediaTypes, serialize };
function serializeSync({ api }) {
const apib = nunjucks.render('template.nunjucks', { api });

return filterExtraSpacing(apib);
}

module.exports = {
name, mediaTypes, serialize, serializeSync,
};
2 changes: 1 addition & 1 deletion packages/apib-serializer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apielements/apib-serializer",
"version": "0.16.1",
"version": "0.16.2",
"description": "API Blueprint serializer for API Elements",
"author": "Apiary.io <[email protected]>",
"license": "MIT",
Expand Down
13 changes: 12 additions & 1 deletion packages/apib-serializer/test/adapter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('API Blueprint serializer adapter', () => {
files.forEach((file) => {
const apib = `${file.substr(0, file.length - 4)}apib`;

it(`serializes ${path.basename(file)}`, (done) => {
it(`serializes ${path.basename(file)} asynchronously`, (done) => {
let serializedRefract;
let expectedBlueprint;
let api;
Expand All @@ -47,6 +47,17 @@ describe('API Blueprint serializer adapter', () => {
return done();
});
});

it(`serializes ${path.basename(file)} synchronously`, () => {
const serializedRefract = require(file);
const expectedBlueprint = fs.readFileSync(apib, 'utf-8');

const parseResult = fury.load(serializedRefract);
const { api } = parseResult;

const serialized = fury.serializeSync({ api });
expect(serialized).to.deep.equal(expectedBlueprint);
});
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dependencies": {
"@apielements/apiaryb-parser": "^0.2.1",
"@apielements/apib-parser": "^0.20.1",
"@apielements/apib-serializer": "^0.16.1",
"@apielements/apib-serializer": "^0.16.2",
"@apielements/core": ">=0.1.0 <0.3.0",
"@apielements/openapi2-parser": "^0.32.3",
"@apielements/openapi3-parser": "^0.15.0",
Expand Down
6 changes: 6 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# API Elements: Core

## 0.2.1 (2020-08-27)

### Enhancements

Added `serializeSync` method to Fury.

## 0.2.0 (2020-08-05)

This package updates the version of `api-elements` being used. See
Expand Down
11 changes: 9 additions & 2 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const mediaTypes = {
```


Adapters are made up of a name, a list of media types, and up to three optional public functions: `detect`, `parse`, and `serialize`. A simple example might look like this:
Adapters are made up of a name, a list of media types, and up to four optional public functions: `detect`, `parse`, `serialize` and `serializeSync`. A simple example might look like this:

```js
export const name = 'my-adapter';
Expand Down Expand Up @@ -176,7 +176,14 @@ export async function serialize({api, mediaType, minim}) {
return outputString;
}

export default {name, mediaTypes, detect, parse, serialize};
export function serializeSync({api, mediaType, minim}) {
// Here you convert `api` from javascript element objects to the serialized
// source format.
// ...
return outputString;
}

export default {name, mediaTypes, detect, parse, serialize, serializeSync};
```

Now you can register your adapter with Fury.js:
Expand Down
39 changes: 37 additions & 2 deletions packages/core/lib/fury.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const minim = new Namespace();

/*
* Find an adapter by a given media type and method name, which should be
* either `parse` or `serialize`. If no adapter is found, then
* either `parse`, `serialize` or `serializeSync`. If no adapter is found, then
* undefined is returned.
*/
const findAdapter = (adapters, mediaType, method) => {
Expand Down Expand Up @@ -80,6 +80,19 @@ const findAdapter = (adapters, mediaType, method) => {
* @memberof FuryAdapter
*/

/**
* @function serializeSync
*
* @param {Object} options
* @param {Category} options.api
* @param {Namespace} options.namespace
*
* @returns {String}
* @throws {Error} error
*
* @memberof FuryAdapter
*/

/**
*/
class Fury {
Expand Down Expand Up @@ -244,6 +257,28 @@ class Fury {
return promise;
}

/**
* Synchronously serialize an API Description into the given output format.
*
* @param {Object} options
* @param {Category} options.api
* @param {string} [options.mediaType]
*/
serializeSync({ api, mediaType = 'text/vnd.apiblueprint' }) {
const adapter = findAdapter(this.adapters, mediaType, 'serializeSync');

if (!adapter) {
throw new Error('Media type did not match any registered serializer!');
}

if (!api) {
// eslint-disable-next-line no-param-reassign
api = new this.minim.elements.Category();
}

return adapter.serializeSync({ api, namespace: this.minim, mediaType });
}

/**
* @callback SerializeCallback
*
Expand All @@ -252,7 +287,7 @@ class Fury {
*/

/**
* Serialize an API Description into the given output format.
* Asynchronously serialize an API Description into the given output format.
*
* @param {Object} options
* @param {Category} options.api
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apielements/core",
"version": "0.2.0",
"version": "0.2.1",
"description": "API Description SDK",
"author": "Apiary.io <[email protected]>",
"license": "MIT",
Expand Down
38 changes: 38 additions & 0 deletions packages/core/test/serialize-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,42 @@ describe('Serialize', () => {
expect(result).to.equal('{"element":"category"}');
});
});

describe('using serializeSync', () => {
it('errors with unknown mediaType', () => {
const fury = new Fury();
const api = new fury.minim.elements.Category();

expect(() => {
fury.serializeSync({ api, mediaType: 'application/unregistered' });
}).to.throw('Media type did not match any registered serializer!');
});

it('can serialize undefined `api` by creating default category', async () => {
const fury = new Fury();
fury.use({
name: 'json',
mediaTypes: ['application/json'],
serializeSync: ({ api, namespace }) => JSON.stringify(namespace.serialiser.serialise(api)),
});

expect(
fury.serializeSync({ api: undefined, mediaType: 'application/json' })
).to.equal('{"element":"category"}');
});

it('can serialize with matching adapter', async () => {
const fury = new Fury();
fury.use({
name: 'json',
mediaTypes: ['application/json'],
serializeSync: ({ api, namespace }) => JSON.stringify(namespace.serialiser.serialise(api)),
});

const api = new fury.minim.elements.Category();

const result = fury.serializeSync({ api, mediaType: 'application/json' });
expect(result).to.equal('{"element":"category"}');
});
});
});
6 changes: 6 additions & 0 deletions packages/form-serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Form Serializer Changelog

## 0.1.3 (2020-08-27)

### Enhancements

- Enable synchronous serialization.

## 0.1.2 (2020-08-19)

### Enhancements
Expand Down
32 changes: 32 additions & 0 deletions packages/form-serializer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,44 @@

## Usage

### Async

```js
const { Fury } = require('@apielements/core');
const formSerializer = require('@apielements/form-serializer');

const fury = new Fury();
fury.use(formSerializer);

const api = new namespace.elements.DataStructure(
new namespace.elements.String('Hello world')
);
const mediaType = 'multipart/form-data';
fury.serialize({ api, mediatype }, (error, body) => {
console.log(body);
// --BOUNDARY\r\nContent-Disposition: form-data; name="undefined"\r\n\r\nHello world\r\n--BOUNDARY--\r\n
});
```

### Sync

```js
const { Fury } = require('@apielements/core');
const formSerializer = require('@apielements/form-serializer');

const fury = new Fury();
fury.use(formSerializer);

const api = new namespace.elements.DataStructure(
new namespace.elements.String('Hello world')
);
const mediaType = 'multipart/form-data';
try {
const body = fury.serializeSync({ api, mediatype });
console.log(body);
// --BOUNDARY\r\nContent-Disposition: form-data; name="undefined"\r\n\r\nHello world\r\n--BOUNDARY--\r\n
} catch (error) {
console.log(error);
// Media type did not match any registered serializer!
}
```
8 changes: 7 additions & 1 deletion packages/form-serializer/lib/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ function serialize({ api, mediaType }) {
return new Promise(resolve => resolve(serializeForm({ api, mediaType })));
}

module.exports = { name, mediaTypes, serialize };
function serializeSync({ api, mediaType }) {
return serializeForm({ api, mediaType });
}

module.exports = {
name, mediaTypes, serialize, serializeSync,
};
2 changes: 1 addition & 1 deletion packages/form-serializer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apielements/form-serializer",
"version": "0.1.2",
"version": "0.1.3",
"description": "Multipart/form-data serializer for API Elements",
"author": "Apiary.io <[email protected]>",
"license": "MIT",
Expand Down
Loading

0 comments on commit e2a8c75

Please sign in to comment.