Skip to content

Commit

Permalink
buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
LorisSigrist committed Oct 12, 2023
1 parent 19998fc commit 4d7dfcb
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 44 deletions.
29 changes: 24 additions & 5 deletions src/core/file-handling/fileHandler.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readFile } from "fs/promises";
import { readFile, writeFile } from "fs/promises";
import { basename } from "path";
import { LoadingException } from "./exception.js";
import { ResultMatcher } from "../utils/resultMatcher.js";
Expand All @@ -17,18 +17,37 @@ export class FileHandler {
* @returns {Promise<Map<string,string>>} A Map of the Key-Value pairs in the file
* @throws {LoadingException} If the file could not be handled
*/
async handle(filePath) {
async read(filePath) {
const handler = this.#getHandler(filePath);
if (!handler)
throw new LoadingException(
`Could not find handler for ${filePath}. Supported file extensions are ${this.getSupportedFileExtensions()}`,
`Could not find handler for ${filePath}. Supported file extensions are ${this.getSupportedFileExtensions()}`
);
const textContent = await this.#readFileContent(filePath);
const keyVal = handler.load(filePath, textContent);

return keyVal;
}

/**
* @param {string} filePath Absolute path to the file that needs to be handled
* @param {string} key
* @param {string} value
* @returns {Promise<void>} A Map of the Key-Value pairs in the file
* @throws {LoadingException} If the file could not be handled
*/
async setPath(filePath, key, value) {
const handler = this.#getHandler(filePath);
if (!handler)
throw new LoadingException(
`Could not find handler for ${filePath}. Supported file extensions are ${this.getSupportedFileExtensions()}`
);

const textContent = await this.#readFileContent(filePath);
const newContent = handler.setPath(textContent, key, value);
await writeFile(filePath, newContent, { encoding: "utf-8" });
}

/**
* Resolved which handler should be used for the given file
* @param {string} filePath
Expand All @@ -39,11 +58,11 @@ export class FileHandler {
const fileExtension = filename.split(".").at(-1);
if (typeof fileExtension !== "string")
throw new LoadingException(
"Could not determine file extension for ${filePath}",
"Could not determine file extension for ${filePath}"
);

const handler = this.#handlers.find((l) =>
l.fileExtensions.includes(fileExtension),
l.fileExtensions.includes(fileExtension)
);

return handler ?? null;
Expand Down
93 changes: 54 additions & 39 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { generateDictionaryModule } from "./codegen/dictionary.js";
import { generateMainModuleCode } from "./codegen/main.js";
import { compileToDictionary } from "./compiler/index.js";
import { Reporter } from "./utils/reporter.js";
import { ResultMatcher } from "./utils/resultMatcher.js";
import { buffer } from "./utils/bufferPromise.js";

/**
* TypeSafe translations for Svelte & SvelteKit.
Expand All @@ -36,6 +38,7 @@ export function t18sCore(pluginConfig) {
/** @type {import("./types.js").LocaleDictionaries} */
const localeDictionaries = new Map();

/** Handles interactions with translation files */
const fileHandler = new FileHandler([YamlHandler, JsonHandler]);

/**
Expand All @@ -45,15 +48,19 @@ export function t18sCore(pluginConfig) {
async function addTranslationFile(filePath) {
const locale = getLocale(filePath);

try {
const keyVal = await fileHandler.handle(filePath);
const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);
if (invalidKeys) reporter.warnAboutInvalidKeys(filePath, invalidKeys);
localeDictionaries.set(locale, dictionary);
} catch (e) {
if (!(e instanceof LoadingException)) throw e;
logger.error(e.message);
}
//Try to read the file & buffer the result
const bufferedFileRead = await buffer(fileHandler.read(filePath));

const keyVal = new ResultMatcher(bufferedFileRead)
.catch(LoadingException, (e) => {
logger.error(e.message);
return new Map();
})
.run();

const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);
if (invalidKeys) reporter.warnAboutInvalidKeys(filePath, invalidKeys);
localeDictionaries.set(locale, dictionary);

await regenerateDTS();
triggerHMREvent("t18s:createLocale", locale);
Expand All @@ -69,18 +76,23 @@ export function t18sCore(pluginConfig) {
async function invalidateTranslationFile(filePath) {
const locale = getLocale(filePath);

try {
const keyVal = await fileHandler.handle(filePath);
const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);
//Try to read the file & buffer the result
const bufferedFileRead = await buffer(fileHandler.read(filePath));

if (invalidKeys) reporter.warnAboutInvalidKeys(filePath, invalidKeys);
else reporter.localeUpdated(locale);
const keyVal = new ResultMatcher(bufferedFileRead)
.catch(LoadingException, (e) => {
logger.error(e.message);
return new Map();
})
.run();

localeDictionaries.set(locale, dictionary);
} catch (e) {
if (!(e instanceof LoadingException)) throw e;
logger.error(e.message);
}

const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);

if (invalidKeys) reporter.warnAboutInvalidKeys(filePath, invalidKeys);
else reporter.localeUpdated(locale);

localeDictionaries.set(locale, dictionary);

await regenerateDTS();
triggerHMREvent("t18s:invalidateLocale", locale);
Expand Down Expand Up @@ -119,28 +131,31 @@ export function t18sCore(pluginConfig) {
* @param { import("./types.js").ResolvedPluginConfig} config
*/
async function loadInitialLocales(config) {
/** @type {string[]} */
let files = [];
try {
files = await readdir(config.translationsDir);
} catch (e) {
logger.error("Could not read translation directory\n" + e);
return;
}
const readdirResult = await buffer(readdir(config.translationsDir));

const files = new ResultMatcher(readdirResult)
.catch(LoadingException, (e) => {
logger.error("Could not read translation directory\n" + e);
return [];
})
.run();

const paths = files.map((file) => resolve(config.translationsDir, file));

/** @param {string} path */
async function loadFile(path) {
const locale = getLocale(path);
try {
const keyVal = await fileHandler.handle(path);
const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);
if (invalidKeys) reporter.warnAboutInvalidKeys(path, invalidKeys);
localeDictionaries.set(locale, dictionary);
} catch (e) {
if (!(e instanceof LoadingException)) throw e;
logger.error(e.message);
}
const readResult = await buffer(fileHandler.read(path));
const keyVal = new ResultMatcher(readResult)
.catch(LoadingException, (e) => {
logger.error(e.message);
return new Map();
})
.run();

const { dictionary, invalidKeys } = compileToDictionary(keyVal, locale);
if (invalidKeys) reporter.warnAboutInvalidKeys(path, invalidKeys);
localeDictionaries.set(locale, dictionary);
}

//Load all locale-files
Expand Down Expand Up @@ -187,7 +202,7 @@ export function t18sCore(pluginConfig) {
});
} else {
logger.error(
`Could not trigger HMR event '${event}' for locale '${locale}' because the viteDevServer is not available. This should never happen.`,
`Could not trigger HMR event '${event}' for locale '${locale}' because the viteDevServer is not available. This should never happen.`
);
}
}
Expand All @@ -201,7 +216,7 @@ export function t18sCore(pluginConfig) {
dtsPath: resolve(resolvedConfig.root, pluginConfig.dts),
translationsDir: resolve(
resolvedConfig.root,
pluginConfig.translationsDir,
pluginConfig.translationsDir
),
verbose: pluginConfig.verbose,
};
Expand All @@ -216,7 +231,7 @@ export function t18sCore(pluginConfig) {
if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {
return id.replace(
VIRTUAL_MODULE_PREFIX,
RESOLVED_VIRTUAL_MODULE_PREFIX,
RESOLVED_VIRTUAL_MODULE_PREFIX
);
}
},
Expand Down
29 changes: 29 additions & 0 deletions src/core/utils/bufferPromise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Await a promise and save the result & errors so that they can be synchronously replayed later.
*
* @template {any} T
* @param {T} promise
*
* @returns {Promise<()=> Awaited<T>>}
*/
export async function buffer(promise) {
/** @type {Awaited<T>} */
let resolvedWith;

/** @type {unknown} */
let rejectedWith;
let rejected = false;


try {
resolvedWith = await promise;
} catch (e) {
rejectedWith = e;
rejected = true;
}

return () => {
if (rejected) throw rejectedWith;
return resolvedWith;
}
}

0 comments on commit 4d7dfcb

Please sign in to comment.