Skip to content

Commit

Permalink
Merge pull request #164 from oat-sa/release-1.22.0
Browse files Browse the repository at this point in the history
Release 1.22.0
  • Loading branch information
shaveko authored Dec 27, 2022
2 parents 108d641 + 694a0fa commit 32537a8
Show file tree
Hide file tree
Showing 11 changed files with 711 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@oat-sa/tao-core-sdk",
"version": "1.21.1",
"version": "1.22.0",
"displayName": "TAO Core SDK",
"description": "Core libraries of TAO",
"homepage": "https://github.com/oat-sa/tao-core-sdk-fe#readme",
Expand Down
29 changes: 29 additions & 0 deletions src/util/converter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2022 (original work) Open Assessment Technologies SA ;
*/

import module from 'module';
import converterFactory from 'util/converter/factory';
import ambiguousSymbolsConverter from 'util/converter/ambiguousSymbols';

/**
* Exposes a default text converter, including all builtin processors.
* It can be configured from the platform through the client registry.
*
* @export 'util/converter'
*/
export default converterFactory([ambiguousSymbolsConverter], module.config());
72 changes: 72 additions & 0 deletions src/util/converter/ambiguousSymbols.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2022 (original work) Open Assessment Technologies SA ;
*/

/**
* Default mapping from ambiguous characters to ASCII.
* @type {object}
*/
const defaultMapping = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'−': '-',
'‐': '-',
'―': '-',
'-': '-'
};

/**
* Converter processor to register with the converter produce by 'util/converter/factory'.
*
* Processor that converts ambiguous unicode symbols into plain ASCII equivalent.
*
* @export 'util/converter/ambiguousSymbols'
*/
export default {
name: 'ambiguousSymbols',

/**
* Converts ambiguous unicode symbols into plain ASCII equivalent.
* @param {string} text - The text to convert.
* @param {object} [config] - An optional config object that may contain processor specific configuration.
* @param {object} [config.ambiguousSymbols] - A specific mapping of ambiguous symbols to plain ASCII chars.
* If omitted the default list will be taken.
* @returns {string} - Returns the converted text.
*/
convert(text, { ambiguousSymbols } = {}) {
let mapping = ambiguousSymbols;

if ('object' !== typeof mapping) {
mapping = defaultMapping;
}

let result = '';
for (const char of text) {
result += mapping[char] || char;
}

return result;
}
};
145 changes: 145 additions & 0 deletions src/util/converter/factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2022 (original work) Open Assessment Technologies SA ;
*/

/**
* Defines a converter processor runtime.
* @callback converterProcessorRuntime
* @param {string} text - The text to convert.
* @param {object} [config] - An optional config object that may contain processor specific configuration.
* @returns {string} - Returns the converted text.
*/

/**
* Defines a converter processor.
* @typedef {object} converterProcessor
* @property {string} name - The name of the converter processor. It needs to be unique within the collection.
* @property {converterProcessorRuntime} convert - The processor runtime that will actually convert the text.
*/

/**
* Creates a text converter.
* @param {converterProcessor[]} builtinProcessors - A list of built-in converter processors.
* @param {object} [builtinConfig] - An optional default config object that may contain processor specific configuration.
* It will be forwarded to each call to the converter.
* @returns {converter} - Returns the text converter, ready for use.
* @export 'util/converter/factory'
*/
export default function converterFactory(builtinProcessors = [], builtinConfig = {}) {
let processors = [];

/**
* @typedef {object} converter
*/
const converter = {
/**
* Converts a text with respect to the registered converter processors.
* @param {string} text - The text to convert.
* @param {object} [config] - An optional config object that may contain processor specific configuration.
* It will be merged with the possible builtin config.
* @returns {string} - Returns the converted text.
*/
convert(text, config = {}) {
const localConfig = Object.assign({}, builtinConfig, config);

for (const processor of processors) {
text = processor.convert.call(converter, text, localConfig);
}

return text;
},

/**
* Registers a converter processor.
* A processor is an object that contains both a `name`, which must be unique,
* and a `convert()` function for converting the given text.
* @param {converterProcessor} processor - The converter processor to register.
* @returns {converter} - Chains the instance.
* @throws {TypeError} - If the processor does not comply with the requirements.
*/
register(processor) {
validateProcessor(processor);

processors.push(processor);

return this;
},

/**
* Unregisters a converter processor.
* @param {string|converterProcessor} name - The name of the processor to remove.
* @returns {converter} - Chains the instance.
*/
unregister(name) {
if ('object' === typeof name) {
name = name.name;
}

processors = processors.filter(processor => processor.name !== name);

return this;
},

/**
* Removes all converter processors.
* @returns {converter} - Chains the instance.
*/
clear() {
processors = [];

return this;
},

/**
* Tells whether a converter processor is registered or not.
* @param {string} name - The name of the processor to check.
* @returns {boolean} - Returns `true` if the converter processor is registered ; returns `false` otherwise.
*/
isRegistered(name) {
return processors.findIndex(processor => processor.name === name) > -1;
}
};

/**
* Checks a converter processor is valid, and throws an error if not.
* @param {converterProcessor} processor - The converter processor to validate.
* @throws {TypeError} - If the processor does not comply with the requirements.
*/
function validateProcessor(processor) {
if ('object' !== typeof processor) {
throw new TypeError('The given processor must be an object!');
}

if ('string' !== typeof processor.name || !processor.name) {
throw new TypeError('A processor needs a name to identify it!');
}

if ('function' !== typeof processor.convert) {
throw new TypeError('A processor needs a runtime function for converting the text!');
}

if (converter.isRegistered(processor.name)) {
throw new TypeError(`The processor "${processor.name}" is already registered!`);
}
}

for (const processor of builtinProcessors) {
converter.register(processor);
}

return converter;
}
21 changes: 21 additions & 0 deletions test/util/converter/ambiguousSymbols/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test - Converter for ambiguous symbols</title>
<script type="text/javascript" src="/environment/require.js"></script>
<script type="text/javascript">
require(['/environment/config.js'], function() {
require(['qunitEnv'], function() {
require(['test/util/converter/ambiguousSymbols/test'], function() {
QUnit.start();
});
});
});
</script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>
70 changes: 70 additions & 0 deletions test/util/converter/ambiguousSymbols/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2022 (original work) Open Assessment Technologies SA ;
*/
define(['util/converter/ambiguousSymbols'], function (converter) {
'use strict';

QUnit.module('converter: ambiguousSymbols');

QUnit.test('module', function (assert) {
assert.equal(typeof converter, 'object', 'The module exposes an object');
});

QUnit.test('API', function (assert) {
assert.equal(converter.name, 'ambiguousSymbols', 'The converter has the expected name');
assert.equal(typeof converter.convert, 'function', 'The converter exposes a "convert" function');
});

QUnit.test('allows to replace the list of ambiguous signs', function (assert) {
const ambiguousSymbols = {
i: '1',
e: '3',
a: '4'
};
const text = '0this is a test0';
const expected = '0th1s 1s 4 t3st0';

assert.equal(
converter.convert(text, { ambiguousSymbols }),
expected,
'The text is converted using the provided list only'
);
});

QUnit.cases
.init([
{ title: '42', expected: '42' },
{ title: '42', expected: '42' },
{ title: '42', expected: '42' },
{ title: '42', expected: '42' },
{ title: 'this is a test', expected: 'this is a test' },
{ title: '42 is the answer', expected: '42 is the answer' },
{ title: '42 is the answer', expected: '42 is the answer' },
{ title: 'the answer is 42', expected: 'the answer is 42' },
{
title: 'japanese 1234567890 ascii 1234567890',
expected: 'japanese 1234567890 ascii 1234567890'
}
])
.test('converts ', function (data, assert) {
assert.strictEqual(
converter.convert(data.title),
data.expected,
`The converter converts "${data.title}" into ${data.expected}`
);
});
});
21 changes: 21 additions & 0 deletions test/util/converter/factory/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test - Converter Factory</title>
<script type="text/javascript" src="/environment/require.js"></script>
<script type="text/javascript">
require(['/environment/config.js'], function() {
require(['qunitEnv'], function() {
require(['test/util/converter/factory/test'], function() {
QUnit.start();
});
});
});
</script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
</body>
</html>
Loading

0 comments on commit 32537a8

Please sign in to comment.