diff --git a/compat_config.js b/compat_config.js index 2e2116817..0e84224c4 100644 --- a/compat_config.js +++ b/compat_config.js @@ -22,7 +22,7 @@ export default { 'plugins': [ // Cf. https://github.com/rollup/rollup-plugin-babel#helpers 'external-helpers', - ['babel-plugin-transform-builtin-extend', { + ['transform-builtin-extend', { globals: ['Error'] }] ] diff --git a/fluent/src/fallback.js b/fluent/src/fallback.js index 7793739c7..5924490c3 100644 --- a/fluent/src/fallback.js +++ b/fluent/src/fallback.js @@ -48,7 +48,6 @@ * @param {string|Array} ids * @returns {MessageContext|Array} */ - export function mapContextSync(iterable, ids) { if (!Array.isArray(ids)) { return getContextForId(iterable, ids); @@ -71,3 +70,36 @@ function getContextForId(iterable, id) { return null; } + +/* + * Asynchronously map an identifier or an array of identifiers to the best + * `MessageContext` instance(s). + * + * @param {AsyncIterable} iterable + * @param {string|Array} ids + * @returns {MessageContext|Array} + */ +export async function mapContextAsync(iterable, ids) { + if (!Array.isArray(ids)) { + for await (const context of iterable) { + if (context.hasMessage(ids)) { + return context; + } + } + } + + const foundContexts = new Array(ids.length).fill(null); + + for await (const context of iterable) { + // XXX Switch to const [index, id] of id.entries() when we move to Babel 7. + // See https://github.com/babel/babel/issues/5880. + for (let index = 0; index < ids.length; index++) { + const id = ids[index]; + if (!foundContexts[index] && context.hasMessage(id)) { + foundContexts[index] = context; + } + } + } + + return foundContexts; +} diff --git a/fluent/src/index.js b/fluent/src/index.js index 4e61c23dc..0bfbfc68b 100644 --- a/fluent/src/index.js +++ b/fluent/src/index.js @@ -17,4 +17,4 @@ export { } from './types'; export { default as CachedIterable } from './cached_iterable'; -export { mapContextSync } from './fallback'; +export { mapContextSync, mapContextAsync } from './fallback'; diff --git a/fluent/test/fallback_async_test.js b/fluent/test/fallback_async_test.js new file mode 100644 index 000000000..16ef0e69b --- /dev/null +++ b/fluent/test/fallback_async_test.js @@ -0,0 +1,87 @@ +import assert from 'assert'; + +import CachedIterable from '../src/cached_iterable'; +import MessageContext from './message_context_stub'; +import { mapContextAsync } from '../src/index'; + +suite('Async Fallback — single id', function() { + let ctx1, ctx2; + + suiteSetup(function() { + ctx1 = new MessageContext(); + ctx1._setMessages(['bar']); + ctx2 = new MessageContext(); + ctx2._setMessages(['foo', 'bar']); + }); + + test('eager iterable', async function() { + const contexts = new CachedIterable([ctx1, ctx2]); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + }); + + test('eager iterable works more than once', async function() { + const contexts = new CachedIterable([ctx1, ctx2]); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + }); + + test('lazy iterable', async function() { + async function *generateMessages() { + yield *[ctx1, ctx2]; + } + + const contexts = new CachedIterable(generateMessages()); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + }); + + test('lazy iterable works more than once', async function() { + async function *generateMessages() { + yield *[ctx1, ctx2]; + } + + const contexts = new CachedIterable(generateMessages()); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + assert.equal(await mapContextAsync(contexts, 'foo'), ctx2); + assert.equal(await mapContextAsync(contexts, 'bar'), ctx1); + }); +}); + +suite('Async Fallback — multiple ids', async function() { + let ctx1, ctx2; + + suiteSetup(function() { + ctx1 = new MessageContext(); + ctx1._setMessages(['foo', 'bar']); + ctx2 = new MessageContext(); + ctx2._setMessages(['foo', 'bar', 'baz']); + }); + + test('existing translations', async function() { + const contexts = new CachedIterable([ctx1, ctx2]); + assert.deepEqual( + await mapContextAsync(contexts, ['foo', 'bar']), + [ctx1, ctx1] + ); + }); + + test('fallback translations', async function() { + const contexts = new CachedIterable([ctx1, ctx2]); + assert.deepEqual( + await mapContextAsync(contexts, ['foo', 'bar', 'baz']), + [ctx1, ctx1, ctx2] + ); + }); + + test('missing translations', async function() { + const contexts = new CachedIterable([ctx1, ctx2]); + assert.deepEqual( + await mapContextAsync(contexts, ['foo', 'bar', 'baz', 'qux']), + [ctx1, ctx1, ctx2, null] + ); + }); +}); diff --git a/fluent/test/fallback_test.js b/fluent/test/fallback_sync_test.js similarity index 96% rename from fluent/test/fallback_test.js rename to fluent/test/fallback_sync_test.js index 4e9520364..7438d2e9d 100644 --- a/fluent/test/fallback_test.js +++ b/fluent/test/fallback_sync_test.js @@ -4,7 +4,7 @@ import CachedIterable from '../src/cached_iterable'; import MessageContext from './message_context_stub'; import { mapContextSync } from '../src/index'; -suite('Fallback — single id', function() { +suite('Sync Fallback — single id', function() { let ctx1, ctx2; suiteSetup(function() { @@ -51,7 +51,7 @@ suite('Fallback — single id', function() { }); }); -suite('Fallback — multiple ids', function() { +suite('Sync Fallback — multiple ids', function() { let ctx1, ctx2; suiteSetup(function() {