Add Akka-Streams to Assess

This commit is contained in:
Carsten Lenz
2017-09-12 22:50:42 +02:00
committed by Tom Raithel
parent 9bac3a27b2
commit 86188db1a7
5 changed files with 123 additions and 129 deletions

View File

@@ -1,43 +1,50 @@
export const featuredOnly = items => items.filter(item => item.isFeatured);
export const groupByQuadrants = (items) => ( export const groupByQuadrants = items =>
items.reduce((quadrants, item) => ({ items.reduce(
...quadrants, (quadrants, item) => ({
[item.quadrant]: addItemToQuadrant(quadrants[item.quadrant], item), ...quadrants,
}), {}) [item.quadrant]: addItemToQuadrant(quadrants[item.quadrant], item),
); }),
{},
);
export const groupByRing = (items) => ( export const groupByRing = items =>
items.reduce((rings, item) => ({ items.reduce(
...rings, (rings, item) => ({
[item.ring]: addItemToList(rings[item.ring], item), ...rings,
}), {}) [item.ring]: addItemToList(rings[item.ring], item),
); }),
{},
);
export const groupByFirstLetter = (items) => { export const groupByFirstLetter = items => {
const index = items.reduce((letterIndex, item) => ({ const index = items.reduce(
...letterIndex, (letterIndex, item) => ({
[getFirstLetter(item)]: addItemToList(letterIndex[getFirstLetter(item)], item), ...letterIndex,
}), {}); [getFirstLetter(item)]: addItemToList(
letterIndex[getFirstLetter(item)],
item,
),
}),
{},
);
return Object.keys(index).sort().map((letter) => ({ return Object.keys(index)
letter, .sort()
items: index[letter], .map(letter => ({
})); letter,
} items: index[letter],
}));
};
const addItemToQuadrant = (quadrant = {}, item) => ({ const addItemToQuadrant = (quadrant = {}, item) => ({
...quadrant, ...quadrant,
[item.ring]: addItemToRing(quadrant[item.ring], item), [item.ring]: addItemToRing(quadrant[item.ring], item),
}); });
const addItemToList = (list = [], item) => ([ const addItemToList = (list = [], item) => [...list, item];
...list,
item,
]);
const addItemToRing = (ring = [], item) => ([ const addItemToRing = (ring = [], item) => [...ring, item];
...ring,
item,
]);
export const getFirstLetter = (item) => item.title.substr(0,1).toUpperCase(); export const getFirstLetter = item => item.title.substr(0, 1).toUpperCase();

View File

@@ -3,17 +3,14 @@ import path from 'path';
import frontmatter from 'front-matter'; import frontmatter from 'front-matter';
import marked from 'marked'; import marked from 'marked';
import hljs from 'highlight.js'; import hljs from 'highlight.js';
import { import { radarPath, getAllMarkdownFiles } from './file';
radarPath,
getAllMarkdownFiles,
} from './file';
marked.setOptions({ marked.setOptions({
highlight: (code) => hljs.highlightAuto(code).value, highlight: code => hljs.highlightAuto(code).value,
}); });
export const createRadar = async (tree) => { export const createRadar = async tree => {
const fileNames = (await getAllMarkdownFiles(radarPath())); const fileNames = await getAllMarkdownFiles(radarPath());
const revisions = await createRevisionsFromFiles(fileNames); const revisions = await createRevisionsFromFiles(fileNames);
const allReleases = getAllReleases(revisions); const allReleases = getAllReleases(revisions);
const items = createItems(revisions); const items = createItems(revisions);
@@ -28,83 +25,80 @@ export const createRadar = async (tree) => {
const checkAttributes = (fileName, attributes) => { const checkAttributes = (fileName, attributes) => {
const rings = ['adopt', 'trial', 'assess', 'hold']; const rings = ['adopt', 'trial', 'assess', 'hold'];
if (attributes.ring && !rings.includes(attributes.ring)) { if (attributes.ring && !rings.includes(attributes.ring)) {
throw new Error(`Error: ${fileName} has an illegal value for 'ring' - must be one of ${rings}`); throw new Error(
`Error: ${fileName} has an illegal value for 'ring' - must be one of ${rings}`,
);
} }
const quadrants = ['languages-and-frameworks', 'methods-and-patterns', 'platforms-and-aoe-services', 'tools']; const quadrants = [
'languages-and-frameworks',
'methods-and-patterns',
'platforms-and-aoe-services',
'tools',
];
if (attributes.quadrant && !quadrants.includes(attributes.quadrant)) { if (attributes.quadrant && !quadrants.includes(attributes.quadrant)) {
throw new Error(`Error: ${fileName} has an illegal value for 'quadrant' - must be one of ${quadrants}`); throw new Error(
`Error: ${fileName} has an illegal value for 'quadrant' - must be one of ${quadrants}`,
);
} }
}; };
const createRevisionsFromFiles = (fileNames) => ( const createRevisionsFromFiles = fileNames =>
Promise.all(fileNames.map((fileName) => { Promise.all(
return new Promise((resolve, reject) => { fileNames.map(fileName => {
readFile(fileName, 'utf8', (err, data) => { return new Promise((resolve, reject) => {
if(err) { readFile(fileName, 'utf8', (err, data) => {
reject(err); if (err) {
} else { reject(err);
const fm = frontmatter(data); } else {
// prepend subfolder to links const fm = frontmatter(data);
fm.body = fm.body.replace(/\]\(\//g, '](/techradar/') // prepend subfolder to links
fm.body = fm.body.replace(/\]\(\//g, '](/techradar/');
// add target attribute to external links // add target attribute to external links
let html = marked(fm.body); let html = marked(fm.body);
html = html.replace(/a href="http/g, 'a target="_blank" href="http') html = html.replace(
/a href="http/g,
'a target="_blank" href="http',
);
checkAttributes(fileName, fm.attributes); checkAttributes(fileName, fm.attributes);
resolve({ resolve({
...itemInfoFromFilename(fileName), ...itemInfoFromFilename(fileName),
...fm.attributes, ...fm.attributes,
fileName, fileName,
body: html body: html,
}); });
} }
});
}); });
}) }),
})) );
);
const itemInfoFromFilename = (fileName) => { const itemInfoFromFilename = fileName => {
const [ const [release, nameWithSuffix] = fileName.split(path.sep).slice(-2);
release,
nameWithSuffix,
] = fileName.split(path.sep).slice(-2);
return { return {
name: nameWithSuffix.substr(0, nameWithSuffix.length - 3), name: nameWithSuffix.substr(0, nameWithSuffix.length - 3),
release, release,
} };
}; };
const getAllReleases = (revisions) => ( const getAllReleases = revisions =>
revisions.reduce((allReleases, { release }) => { revisions
if(!allReleases.includes(release)) { .reduce((allReleases, { release }) => {
return [...allReleases, release]; if (!allReleases.includes(release)) {
} return [...allReleases, release];
return allReleases; }
}, []).sort() return allReleases;
); }, [])
.sort();
// const createQuadrants = (revisions) => (
// revisions.reduce((quadrants, revision) => {
// return {
// ...quadrants,
// [revision.quadrant]: addRevisionToQuadrant(quadrants[revision.quadrant], revision),
// };
// }, {})
// );
// const addRevisionToQuadrant = (quadrant = {}, revision) => ({
// ...quadrant,
// [revision.name]: addRevisionToItem(quadrant[revision.name], revision),
// });
const addRevisionToQuadrant = (quadrant = {}, revision) => ({ const addRevisionToQuadrant = (quadrant = {}, revision) => ({
...quadrant, ...quadrant,
[revision.ring]: addRevisionToRing(quadrant[revision.ring], revision), [revision.ring]: addRevisionToRing(quadrant[revision.ring], revision),
}); });
const createItems = (revisions) => { const createItems = revisions => {
const itemMap = revisions.reduce((items, revision) => { const itemMap = revisions.reduce((items, revision) => {
return { return {
...items, ...items,
@@ -112,21 +106,18 @@ const createItems = (revisions) => {
}; };
}, {}); }, {});
return Object return Object.values(itemMap).sort((x, y) => (x.name > y.name ? 1 : -1));
.values(itemMap)
.sort((x, y) => (x.name > y.name ? 1 : -1));
}; };
const addRevisionToItem = (item = { const addRevisionToItem = (
attributes: { item = {
isNew: false,
isFeatured: true, isFeatured: true,
revisions: [],
}, },
revisions: [], revision,
}, revision) => { ) => {
const { const { fileName, ...rest } = revision;
fileName,
...rest,
} = revision;
let newItem = { let newItem = {
...item, ...item,
...rest, ...rest,
@@ -139,28 +130,29 @@ const addRevisionToItem = (item = {
if (revisionCreatesNewHistoryEntry(revision)) { if (revisionCreatesNewHistoryEntry(revision)) {
newItem = { newItem = {
...newItem, ...newItem,
revisions: [ revisions: [rest, ...newItem.revisions],
rest, };
...newItem.revisions,
],
}
} }
return newItem; return newItem;
}; };
const revisionCreatesNewHistoryEntry = (revision) => { const revisionCreatesNewHistoryEntry = revision => {
return revision.body.trim() !== '' || return revision.body.trim() !== '' || typeof revision.ring !== 'undefined';
typeof revision.ring !== 'undefined';
}; };
const flagWithIsNew = (items, allReleases) => ( const flagWithIsNew = (items, allReleases) =>
items.map((item) => ({ items.map(
...item, item => ({
isNew: isNewItem(item, allReleases), ...item,
}), []) isNew: isNewItem(item, allReleases),
); }),
[],
);
const isNewItem = (item, allReleases) => { const isNewItem = (item, allReleases) => {
return item.revisions.length > 1 && item.revisions[0].release === allReleases[allReleases.length-1] return (
item.revisions.length === 0 ||
item.revisions[0].release === allReleases[allReleases.length - 1]
);
}; };

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { formatRelease } from '../date'; import { formatRelease } from '../date';
import { featuredOnly } from '../../common/model';
import HeroHeadline from './HeroHeadline'; import HeroHeadline from './HeroHeadline';
import QuadrantGrid from './QuadrantGrid'; import QuadrantGrid from './QuadrantGrid';
import Fadeable from './Fadeable'; import Fadeable from './Fadeable';
@@ -22,7 +23,7 @@ export default function PageIndex({
AOE Technology Radar AOE Technology Radar
</HeroHeadline> </HeroHeadline>
</div> </div>
<QuadrantGrid items={items} /> <QuadrantGrid items={featuredOnly(items)} />
</Fadeable> </Fadeable>
); );
} }

View File

@@ -1,5 +0,0 @@
---
ring: adopt
---
TODO: Updated text here!

View File

@@ -6,14 +6,14 @@ quadrant: languages-and-frameworks
--- ---
In our backend services we frequently encounter the task to transform data In our backend services we frequently encounter the task to transform data
coming from and uploading to external sources and services. coming from and uploading to external sources and services.
Building more complex data transformation processes with Akka Actors has proven Building more complex data transformation processes with Akka Actors has proven
very difficult for us in the past. very difficult for us in the past.
Seeing this data as a stream of elements could allow to handle them piece by Seeing this data as a stream of elements could allow to handle them piece by
piece and only keeping as much of the data in-process as can currently be piece and only keeping as much of the data in-process as can currently be
handled. handled.
[Akka Streams](http://doc.akka.io/docs/akka/current/scala/stream/index.html) is [Akka Streams](http://doc.akka.io/docs/akka/current/scala/stream/index.html) is
a [Reactive Streams](http://www.reactive-streams.org/) implementation that a [Reactive Streams](http://www.reactive-streams.org/) implementation that
@@ -31,4 +31,3 @@ more complex services with it.
We will continue looking into it together with the We will continue looking into it together with the
[Alpakka](/languages-and-frameworks/alpakka.html) Connectors for integration [Alpakka](/languages-and-frameworks/alpakka.html) Connectors for integration
work. work.