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

Commit ec131f1

Browse files
authored
feat(text): add text serializer (#555)
1 parent 6197f8d commit ec131f1

File tree

8 files changed

+317
-0
lines changed

8 files changed

+317
-0
lines changed

Diff for: commitlint.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module.exports = {
1212
'remote',
1313
'form',
1414
'json',
15+
'text',
1516
'deps',
1617
'deps-dev',
1718
]],

Diff for: packages/text-serializer/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Text Serializer Changelog
2+
3+
## 0.1.0
4+
5+
Initial release

Diff for: packages/text-serializer/README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# API Elements: Text Serializer
2+
3+
## Usage
4+
5+
Takes an API Element data structure, and returns Text serialized data
6+
structures, for example:
7+
8+
### Async
9+
10+
```javascript
11+
const { Fury } = require('@apielements/core');
12+
const textSerializer = require('@apielements/text-serializer');
13+
14+
const fury = new Fury();
15+
fury.use(textSerializer);
16+
17+
const api = new fury.minim.elements.String();
18+
api.attributes.set('default', 'Doe');
19+
20+
const mediaType = 'text/plain';
21+
fury.serialize({ api, mediaType }, (error, body) => {
22+
console.log(body);
23+
// "Doe"
24+
});
25+
```
26+
27+
28+
### Sync
29+
30+
```javascript
31+
const { Fury } = require('@apielements/core');
32+
const textSerializer = require('@apielements/text-serializer');
33+
34+
const fury = new Fury();
35+
fury.use(textSerializer);
36+
37+
const api = new fury.minim.elements.String('Doe');
38+
const mediaType = 'text/plain';
39+
try {
40+
const body = fury.serialize({ api, mediaType });
41+
console.log(body);
42+
// Doe
43+
} catch (error) {
44+
console.log(error);
45+
// Only primitive elements can be serialized as text/plain
46+
}
47+
```

Diff for: packages/text-serializer/lib/adapter.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const serializeText = require('./serializeText');
2+
3+
const name = 'text';
4+
const mediaTypes = [
5+
'text/plain',
6+
];
7+
8+
function serialize({ api }) {
9+
return new Promise((resolve, reject) => {
10+
const done = (error, result) => {
11+
if (error) {
12+
reject(error);
13+
} else {
14+
resolve(result);
15+
}
16+
};
17+
18+
serializeText(api, done);
19+
});
20+
}
21+
22+
function serializeSync({ api }) {
23+
const done = (error, result) => {
24+
if (error) {
25+
throw error;
26+
} else {
27+
return result;
28+
}
29+
};
30+
31+
return serializeText(api, done);
32+
}
33+
34+
module.exports = {
35+
name, mediaTypes, serialize, serializeSync,
36+
};

Diff for: packages/text-serializer/lib/serializeText.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
function collectElementByIDs(element) {
2+
const dataStructures = {};
3+
const { parents } = element;
4+
5+
if (!parents || parents.isEmpty) {
6+
return dataStructures;
7+
}
8+
9+
const rootElement = parents.get(parents.length - 1);
10+
11+
if (rootElement) {
12+
rootElement.recursiveChildren.forEach((element) => {
13+
// eslint-disable-next-line no-underscore-dangle
14+
const isNotEmptyStringElement = element._meta && element._meta.get('id');
15+
16+
if (isNotEmptyStringElement) {
17+
dataStructures[element.id.toValue()] = element;
18+
}
19+
});
20+
}
21+
22+
return dataStructures;
23+
}
24+
25+
const isPrimitive = value => value !== undefined && (value !== Object(value));
26+
27+
function serializeText(element, done) {
28+
if (element.element === 'dataStructure') {
29+
return serializeText(element.content, done);
30+
}
31+
32+
const dataStructures = collectElementByIDs(element);
33+
const value = element.valueOf(undefined, dataStructures);
34+
35+
if (isPrimitive(value)) {
36+
return done(null, String(value));
37+
}
38+
39+
return done(new Error('Only primitive elements can be serialized as text/plain'));
40+
}
41+
42+
module.exports = serializeText;

Diff for: packages/text-serializer/package.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@apielements/text-serializer",
3+
"version": "0.1.0",
4+
"description": "Text serializer for API Elements",
5+
"author": "Apiary.io <[email protected]>",
6+
"license": "MIT",
7+
"main": "./lib/adapter.js",
8+
"files": [
9+
"lib/adapter.js",
10+
"lib/serializeText.js"
11+
],
12+
"homepage": "https://github.com/apiaryio/api-elements.js/tree/master/packages/text-serializer",
13+
"repository": {
14+
"type": "git",
15+
"url": "https://github.com/apiaryio/api-elements.js.git",
16+
"directory": "packages/text-serializer"
17+
},
18+
"scripts": {
19+
"lint": "eslint .",
20+
"lint:fix": "eslint . --fix",
21+
"test": "mocha test"
22+
},
23+
"peerDependencies": {
24+
"@apielements/core": ">=0.1.0 <0.3.0"
25+
},
26+
"devDependencies": {
27+
"@apielements/core": ">=0.1.0 <0.3.0",
28+
"chai": "^4.2.0",
29+
"eslint": "^5.16.0",
30+
"mocha": "^7.1.1"
31+
},
32+
"engines": {
33+
"node": ">=8"
34+
}
35+
}

Diff for: packages/text-serializer/test/adapter-test.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const { expect } = require('chai');
2+
const { Fury } = require('@apielements/core');
3+
const adapter = require('../lib/adapter');
4+
5+
describe('Text Serializer Adapter', () => {
6+
let fury;
7+
8+
before(() => {
9+
fury = new Fury();
10+
fury.use(adapter);
11+
});
12+
13+
it('has a name', () => {
14+
expect(adapter.name).to.equal('text');
15+
});
16+
17+
it('has a text/plain media type', () => {
18+
expect(adapter.mediaTypes).to.deep.equal(['text/plain']);
19+
});
20+
21+
describe('using serialize', () => {
22+
it('can serialize a primitive element', (done) => {
23+
const element = new fury.minim.elements.String('hello world');
24+
25+
fury.serialize({ api: element, mediaType: 'text/plain' }, (error, result) => {
26+
expect(error).to.be.null;
27+
expect(result).to.equal('hello world');
28+
done();
29+
});
30+
});
31+
32+
it('errors with a non-primitive element', (done) => {
33+
const element = new fury.minim.elements.Object({ message: 'Hello world' });
34+
35+
fury.serialize({ api: element, mediaType: 'text/plain' }, (error, result) => {
36+
expect(error.message).to.equal('Only primitive elements can be serialized as text/plain');
37+
expect(result).to.be.undefined;
38+
done();
39+
});
40+
});
41+
});
42+
43+
describe('using serializeSync', () => {
44+
it('can serialize a primitive element', () => {
45+
const element = new fury.minim.elements.String('hello world');
46+
const result = fury.serializeSync({ api: element, mediaType: 'text/plain' });
47+
48+
expect(result).to.equal('hello world');
49+
});
50+
51+
it('errors with a non-primitive element', () => {
52+
const element = new fury.minim.elements.Object({ message: 'Hello world' });
53+
54+
expect(() => fury.serializeSync({ api: element, mediaType: 'text/plain' }))
55+
.to.throw('Only primitive elements can be serialized as text/plain');
56+
});
57+
});
58+
});

Diff for: packages/text-serializer/test/serializeText-test.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const { expect } = require('chai');
2+
const { Fury } = require('@apielements/core');
3+
const serializeText = require('../lib/serializeText');
4+
5+
const { minim: namespace } = new Fury();
6+
7+
const done = (error, result) => {
8+
if (error) {
9+
throw error;
10+
} else {
11+
return result;
12+
}
13+
};
14+
15+
describe('#serializeText', () => {
16+
it('can serialize a primitive element with value', () => {
17+
const stringElement = new namespace.elements.String('hello world');
18+
const numberElement = new namespace.elements.Number(1);
19+
const booleanElement = new namespace.elements.Boolean(true);
20+
const nullElement = new namespace.elements.Null();
21+
22+
expect(serializeText(stringElement, done)).to.equal('hello world');
23+
expect(serializeText(numberElement, done)).to.equal('1');
24+
expect(serializeText(booleanElement, done)).to.equal('true');
25+
expect(serializeText(nullElement, done)).to.equal('null');
26+
});
27+
28+
it('can serialize an enum element with primitive values', () => {
29+
const enumElement = new namespace.elements.Enum();
30+
enumElement.enumerations = ['north', 'east', 'south', 'west'];
31+
32+
expect(serializeText(enumElement, done)).to.equal('north');
33+
});
34+
35+
it('can serialize a primitive element with default value', () => {
36+
const element = new namespace.elements.String();
37+
element.attributes.set('default', 'hello world');
38+
39+
expect(serializeText(element, done)).to.equal('hello world');
40+
});
41+
42+
it('can serialize an element with references via parent tree', () => {
43+
const element = new namespace.elements.Element();
44+
element.element = 'error';
45+
46+
const error = new namespace.elements.Element();
47+
error.element = 'message';
48+
error.id = 'error';
49+
50+
new namespace.elements.Category([
51+
new namespace.elements.Category([
52+
new namespace.elements.String('error message', { id: 'message' }),
53+
error,
54+
], { classes: ['dataStructures'] }),
55+
new namespace.elements.Category([
56+
element,
57+
]),
58+
]).freeze();
59+
60+
expect(serializeText(element, done)).to.equal('error message');
61+
});
62+
63+
it('can serialize a dataStructure element', () => {
64+
const element = new namespace.elements.DataStructure(
65+
new namespace.elements.String('hello world')
66+
);
67+
68+
expect(serializeText(element, done)).to.equal('hello world');
69+
});
70+
71+
it('can serialize from referenced element', () => {
72+
const element = new namespace.elements.Element();
73+
element.element = 'ref';
74+
element.content = 'message';
75+
76+
new namespace.elements.Category([
77+
new namespace.elements.String('hello world', { id: 'message' }),
78+
element,
79+
]).freeze();
80+
81+
expect(serializeText(element, done)).to.equal('hello world');
82+
});
83+
84+
it('errors with a non primitive element', () => {
85+
const objectElement = new namespace.elements.Object({ message: 'Hello world' });
86+
const arrayElement = new namespace.elements.Array(['Hello', 'Doe']);
87+
const emptyEnumElement = new namespace.elements.Enum();
88+
89+
expect(() => serializeText(objectElement, done)).to.throw('Only primitive elements can be serialized as text/plain');
90+
expect(() => serializeText(arrayElement, done)).to.throw('Only primitive elements can be serialized as text/plain');
91+
expect(() => serializeText(emptyEnumElement, done)).to.throw('Only primitive elements can be serialized as text/plain');
92+
});
93+
});

0 commit comments

Comments
 (0)