Refactor createNote (#1789)

* Update createNote to return a wrapper object

* Update how createNote creates errors
This commit is contained in:
toasted-nutbread 2021-07-03 11:30:48 -04:00 committed by GitHub
parent d7c934cae8
commit f7d177e6d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 49 deletions

View File

@ -42,8 +42,7 @@ class AnkiNoteBuilder {
duplicateScope='collection', duplicateScope='collection',
resultOutputMode='split', resultOutputMode='split',
glossaryLayoutMode='default', glossaryLayoutMode='default',
compactTags=false, compactTags=false
errors=null
}) { }) {
let duplicateScopeDeckName = null; let duplicateScopeDeckName = null;
let duplicateScopeCheckChildren = false; let duplicateScopeCheckChildren = false;
@ -53,6 +52,7 @@ class AnkiNoteBuilder {
duplicateScopeCheckChildren = true; duplicateScopeCheckChildren = true;
} }
const errors = [];
const commonData = this._createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, injectedMedia); const commonData = this._createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, injectedMedia);
const formattedFieldValuePromises = []; const formattedFieldValuePromises = [];
for (const [, fieldValue] of fields) { for (const [, fieldValue] of fields) {
@ -68,7 +68,7 @@ class AnkiNoteBuilder {
noteFields[fieldName] = formattedFieldValue; noteFields[fieldName] = formattedFieldValue;
} }
return { const note = {
fields: noteFields, fields: noteFields,
tags, tags,
deckName, deckName,
@ -82,6 +82,7 @@ class AnkiNoteBuilder {
} }
} }
}; };
return {note, errors};
} }
async getRenderingData({ async getRenderingData({
@ -112,17 +113,15 @@ class AnkiNoteBuilder {
}; };
} }
async _formatField(field, commonData, template, errors=null) { async _formatField(field, commonData, template, errors) {
return await this._stringReplaceAsync(field, this._markerPattern, async (g0, marker) => { return await this._stringReplaceAsync(field, this._markerPattern, async (g0, marker) => {
try { try {
const {result} = await this._renderTemplateBatched(template, commonData, marker); const {result} = await this._renderTemplateBatched(template, commonData, marker);
return result; return result;
} catch (e) { } catch (e) {
if (Array.isArray(errors)) {
const error = new Error(`Template render error for {${marker}}`); const error = new Error(`Template render error for {${marker}}`);
error.data = {error: e}; error.data = {error: e};
errors.push(error); errors.push(error);
}
return `{${marker}-render-error}`; return `{${marker}-render-error}`;
} }
}); });

View File

@ -1259,12 +1259,13 @@ class Display extends EventDispatcher {
this._hideAnkiNoteErrors(true); this._hideAnkiNoteErrors(true);
const errors = []; const allErrors = [];
const overrideToken = this._progressIndicatorVisible.setOverride(true); const overrideToken = this._progressIndicatorVisible.setOverride(true);
try { try {
const {anki: {suspendNewCards}} = this._options; const {anki: {suspendNewCards}} = this._options;
const noteContext = this._getNoteContext(); const noteContext = this._getNoteContext();
const note = await this._createNote(dictionaryEntry, mode, noteContext, true, errors); const {note, errors} = await this._createNote(dictionaryEntry, mode, noteContext, true);
allErrors.push(...errors);
let noteId = null; let noteId = null;
let addNoteOkay = false; let addNoteOkay = false;
@ -1272,19 +1273,19 @@ class Display extends EventDispatcher {
noteId = await yomichan.api.addAnkiNote(note); noteId = await yomichan.api.addAnkiNote(note);
addNoteOkay = true; addNoteOkay = true;
} catch (e) { } catch (e) {
errors.length = 0; allErrors.length = 0;
errors.push(e); allErrors.push(e);
} }
if (addNoteOkay) { if (addNoteOkay) {
if (noteId === null) { if (noteId === null) {
errors.push(new Error('Note could not be added')); allErrors.push(new Error('Note could not be added'));
} else { } else {
if (suspendNewCards) { if (suspendNewCards) {
try { try {
await yomichan.api.suspendAnkiCardsForNote(noteId); await yomichan.api.suspendAnkiCardsForNote(noteId);
} catch (e) { } catch (e) {
errors.push(e); allErrors.push(e);
} }
} }
button.disabled = true; button.disabled = true;
@ -1292,13 +1293,13 @@ class Display extends EventDispatcher {
} }
} }
} catch (e) { } catch (e) {
errors.push(e); allErrors.push(e);
} finally { } finally {
this._progressIndicatorVisible.clearOverride(overrideToken); this._progressIndicatorVisible.clearOverride(overrideToken);
} }
if (errors.length > 0) { if (allErrors.length > 0) {
this._showAnkiNoteErrors(errors); this._showAnkiNoteErrors(allErrors);
} else { } else {
this._hideAnkiNoteErrors(true); this._hideAnkiNoteErrors(true);
} }
@ -1480,11 +1481,11 @@ class Display extends EventDispatcher {
const notePromises = []; const notePromises = [];
for (const dictionaryEntry of dictionaryEntries) { for (const dictionaryEntry of dictionaryEntries) {
for (const mode of modes) { for (const mode of modes) {
const notePromise = this._createNote(dictionaryEntry, mode, context, false, null); const notePromise = this._createNote(dictionaryEntry, mode, context, false);
notePromises.push(notePromise); notePromises.push(notePromise);
} }
} }
const notes = await Promise.all(notePromises); const notes = (await Promise.all(notePromises)).map(({note}) => note);
let infos; let infos;
if (forceCanAddValue !== null) { if (forceCanAddValue !== null) {
@ -1512,7 +1513,7 @@ class Display extends EventDispatcher {
return results; return results;
} }
async _createNote(dictionaryEntry, mode, context, injectMedia, errors) { async _createNote(dictionaryEntry, mode, context, injectMedia) {
const options = this._options; const options = this._options;
const template = this._ankiFieldTemplates; const template = this._ankiFieldTemplates;
const { const {
@ -1524,18 +1525,17 @@ class Display extends EventDispatcher {
const {deck: deckName, model: modelName} = modeOptions; const {deck: deckName, model: modelName} = modeOptions;
const fields = Object.entries(modeOptions.fields); const fields = Object.entries(modeOptions.fields);
const errors = [];
let injectedMedia = null; let injectedMedia = null;
if (injectMedia) { if (injectMedia) {
let errors2; let errors2;
({result: injectedMedia, errors: errors2} = await this._injectAnkiNoteMedia(dictionaryEntry, options, fields)); ({result: injectedMedia, errors: errors2} = await this._injectAnkiNoteMedia(dictionaryEntry, options, fields));
if (Array.isArray(errors)) {
for (const error of errors2) { for (const error of errors2) {
errors.push(deserializeError(error)); errors.push(deserializeError(error));
} }
} }
}
return await this._ankiNoteBuilder.createNote({ const {note, errors: createNoteErrors} = await this._ankiNoteBuilder.createNote({
dictionaryEntry, dictionaryEntry,
mode, mode,
context, context,
@ -1552,6 +1552,8 @@ class Display extends EventDispatcher {
injectedMedia, injectedMedia,
errors errors
}); });
errors.push(...createNoteErrors);
return {note, errors};
} }
async _injectAnkiNoteMedia(dictionaryEntry, options, fields) { async _injectAnkiNoteMedia(dictionaryEntry, options, fields) {
@ -1959,20 +1961,16 @@ class Display extends EventDispatcher {
const ankiNotes = []; const ankiNotes = [];
const modes = this._getModes(dictionaryEntry.type === 'term'); const modes = this._getModes(dictionaryEntry.type === 'term');
for (const mode of modes) { for (const mode of modes) {
let ankiNote; let note;
let ankiNoteException; let errors;
const errors = [];
try { try {
const noteContext = this._getNoteContext(); const noteContext = this._getNoteContext();
ankiNote = await this._createNote(dictionaryEntry, mode, noteContext, false, errors); ({note: note, errors} = await this._createNote(dictionaryEntry, mode, noteContext, false));
} catch (e) { } catch (e) {
ankiNoteException = e; errors = [e];
} }
const entry = {mode, ankiNote}; const entry = {mode, note};
if (typeof ankiNoteException !== 'undefined') { if (Array.isArray(errors) && errors.length > 0) {
entry.ankiNoteException = ankiNoteException;
}
if (errors.length > 0) {
entry.errors = errors; entry.errors = errors;
} }
ankiNotes.push(entry); ankiNotes.push(entry);

View File

@ -147,8 +147,8 @@ class AnkiTemplatesController {
} }
async _validate(infoNode, field, mode, showSuccessResult, invalidateInput) { async _validate(infoNode, field, mode, showSuccessResult, invalidateInput) {
const allErrors = [];
const text = this._renderTextInput.value || ''; const text = this._renderTextInput.value || '';
const errors = [];
let result = `No definition found for ${text}`; let result = `No definition found for ${text}`;
try { try {
const optionsContext = this._settingsController.getOptionsContext(); const optionsContext = this._settingsController.getOptionsContext();
@ -168,7 +168,7 @@ class AnkiTemplatesController {
let template = options.anki.fieldTemplates; let template = options.anki.fieldTemplates;
if (typeof template !== 'string') { template = this._defaultFieldTemplates; } if (typeof template !== 'string') { template = this._defaultFieldTemplates; }
const {general: {resultOutputMode, glossaryLayoutMode, compactTags}} = options; const {general: {resultOutputMode, glossaryLayoutMode, compactTags}} = options;
const note = await this._ankiNoteBuilder.createNote({ const {note, errors} = await this._ankiNoteBuilder.createNote({
dictionaryEntry, dictionaryEntry,
mode, mode,
context, context,
@ -180,13 +180,13 @@ class AnkiTemplatesController {
], ],
resultOutputMode, resultOutputMode,
glossaryLayoutMode, glossaryLayoutMode,
compactTags, compactTags
errors
}); });
result = note.fields.field; result = note.fields.field;
allErrors.push(...errors);
} }
} catch (e) { } catch (e) {
errors.push(e); allErrors.push(e);
} }
const errorToMessageString = (e) => { const errorToMessageString = (e) => {
@ -205,9 +205,9 @@ class AnkiTemplatesController {
return `${e}`; return `${e}`;
}; };
const hasError = errors.length > 0; const hasError = allErrors.length > 0;
infoNode.hidden = !(showSuccessResult || hasError); infoNode.hidden = !(showSuccessResult || hasError);
infoNode.textContent = hasError ? errors.map(errorToMessageString).join('\n') : (showSuccessResult ? result : ''); infoNode.textContent = hasError ? allErrors.map(errorToMessageString).join('\n') : (showSuccessResult ? result : '');
infoNode.classList.toggle('text-danger', hasError); infoNode.classList.toggle('text-danger', hasError);
if (invalidateInput) { if (invalidateInput) {
this._fieldTemplatesTextarea.dataset.invalid = `${hasError}`; this._fieldTemplatesTextarea.dataset.invalid = `${hasError}`;

View File

@ -219,8 +219,7 @@ async function getRenderResults(dictionaryEntries, type, mode, template, AnkiNot
query: 'query', query: 'query',
fullQuery: 'fullQuery' fullQuery: 'fullQuery'
}; };
const errors = []; const {note: {fields: noteFields}, errors} = await ankiNoteBuilder.createNote({
const noteFields = (await ankiNoteBuilder.createNote({
dictionaryEntry, dictionaryEntry,
mode: null, mode: null,
context, context,
@ -234,11 +233,10 @@ async function getRenderResults(dictionaryEntries, type, mode, template, AnkiNot
duplicateScope: 'collection', duplicateScope: 'collection',
resultOutputMode: mode, resultOutputMode: mode,
glossaryLayoutMode: 'default', glossaryLayoutMode: 'default',
compactTags: false, compactTags: false
errors });
})).fields;
if (!write) { if (!write) {
assert.deepStrictEqual(errors, []); assert.strictEqual(errors.length, 0);
} }
results.push(noteFields); results.push(noteFields);
} }