Skip to content

Commit

Permalink
A little reorganizing
Browse files Browse the repository at this point in the history
  • Loading branch information
LorisSigrist committed Oct 23, 2023
1 parent d3149c2 commit feaf5f7
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 158 deletions.
18 changes: 0 additions & 18 deletions packages/t18s/src/core/codegen/config.js

This file was deleted.

151 changes: 31 additions & 120 deletions packages/t18s/src/core/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { basename, dirname, resolve } from "node:path";
import { basename, resolve } from "node:path";
import { readdir, writeFile } from "node:fs/promises";
import { YamlHandler } from "./file-handling/formats/yaml.js";
import { JsonHandler } from "./file-handling/formats/json.js";
import { Logger } from "./utils/logger.js";
import { FileHandler } from "./file-handling/fileHandler.js";
import { LoadingException } from "./file-handling/exception.js";
import { generateDTS } from "./codegen/dts.js";
import { generateDictionaryModule } from "./codegen/dictionary.js";
import { resolveMainModuleId } from "./codegen/main.js";
import { resolveMainModuleId } from "./module-resolution/main.js";
import { compileToDictionary } from "./utils/compileToDictionary.js";
import { Reporter } from "./utils/reporter.js";
import { ResultMatcher } from "./utils/resultMatcher.js";
Expand All @@ -16,12 +15,21 @@ import {
MessageCatalogue,
LocaleNotFoundException,
} from "./MessageCatalogue.js";
import { normalizePath } from "vite";
import { fileURLToPath } from "node:url";
import { cleanUrl } from "./utils/id.js";
import { createHMRDispatcher } from "./HMR.js";
import { generateConfigModule } from "./codegen/config.js";
import { generateLoaderModule } from "./codegen/loaders.js";
import {
loadDictionaryModule,
resolveDictionaryModuleId,
} from "./module-resolution/dictionary.js";
import {
loadConfigModule,
resolveConfigModuleId,
} from "./module-resolution/config.js";
import {
loadLoaderModule,
resolveLoaderModuleId,
} from "./module-resolution/loader.js";
import { resolveIdSequence } from "./module-resolution/utils.js";

/**
* TypeSafe translations for Svelte & SvelteKit.
Expand Down Expand Up @@ -210,19 +218,6 @@ export function t18sCore(pluginConfig) {
await writeFile(config.dtsPath, generateDTS(config, Catalogue));
}

/**
* Categorizes to which locale & domain a given file belongs.
* @param {string} path
*/
const categorizeFile = (path) => {
const filename = basename(path).split(".").slice(0, -1).join(".");

const [first, second] = filename.split(".");
if (!first) throw new Error(`Could not determine locale for ${path}`);
if (!second) throw new Error(`Could not determine domain for ${path}`);
return { locale: second, domain: first };
};

return {
name: "t18s",
enforce: "pre",
Expand All @@ -246,27 +241,17 @@ export function t18sCore(pluginConfig) {
await loadInitialLocales(config);
},

resolveId(id) {
id = cleanUrl(id);

const resolvers = [
resolveDictionaryModuleId,
resolveMainModuleId,
resolveConfigModuleId,
resolveLoaderModuleId,
];

for (const resolver of resolvers) {
const resolved = resolver(id);
if (resolved) return resolved;
}

return null;
},
resolveId: resolveIdSequence([
resolveDictionaryModuleId,
resolveMainModuleId,
resolveConfigModuleId,
resolveLoaderModuleId,
]),

async load(id) {
id = cleanUrl(id);

/** @type {import("./module-resolution/types.js").ModuleLoader[]} */
const loaders = [
loadDictionaryModule,
loadConfigModule,
Expand Down Expand Up @@ -322,90 +307,16 @@ export function t18sCore(pluginConfig) {
};
}

function getRuntimeEntryPath() {
const thisModulePath = normalizePath(dirname(fileURLToPath(import.meta.url)));
return thisModulePath.replace(
/\/t18s\/src\/core$/,
"/t18s/src/core/runtime/"
);
}

/**
* Returns the code for the dictionary module if the resolved_id is for the main module.
* @param {string} resolved_id
* @param {import("./types.js").ResolvedPluginConfig} config
* @param {MessageCatalogue} Catalogue
* @returns {Promise<string | null>}
* Categorizes to which locale & domain a given file belongs.
* @param {string} path
* @returns {{locale: string, domain: string}}
*/
async function loadDictionaryModule(resolved_id, config, Catalogue) {
if (!resolved_id.startsWith("\0t18s-dictionary:")) return null;

const [_, locale, domain] = resolved_id.split(":");
if (!locale || !domain) return null;
function categorizeFile(path) {
const filename = basename(path).split(".").slice(0, -1).join(".");

const dictionary = Catalogue.getDictionary(locale, domain);

return dictionary
? generateDictionaryModule(dictionary)
: "export default {}";
}

/**
* @param {string} resolved_id
* @param {import("./types.js").ResolvedPluginConfig} config
*
* @param {MessageCatalogue} Catalogue
* @returns {Promise<string | null>}
*/
async function loadConfigModule(resolved_id, config, Catalogue) {
if (resolved_id !== "\0t18s-internal:config") return null;
return generateConfigModule(config);
}

/**
* @param {string} resolved_id
* @param {import("./types.js").ResolvedPluginConfig} config
*
* @param {MessageCatalogue} Catalogue
* @returns {Promise<string | null>}
*/
async function loadLoaderModule(resolved_id, config, Catalogue) {
if (resolved_id !== "\0t18s-internal:loaders") return null;
return generateLoaderModule(config, Catalogue);
}

/**
* If the unresolved_id is for a t18s dictionary, this function will resolve it.
* Dictionary modules have the format "t18s-dictionary:<locale>:<domain>"
*
* @param {string} unresolved_id
* @returns {string | null}
*/
function resolveDictionaryModuleId(unresolved_id) {
if (!unresolved_id.startsWith("t18s-dictionary:")) return null;

const [_, locale, domain] = unresolved_id.split(":");
if (!locale || !domain) return null;

const resolved_id = "\0" + unresolved_id;
return resolved_id;
}

/**
* If the unresolved_id is for the t18s config, this function will resolve it.
* @param {string} unresolved_id
* @returns {string | null}
*/
function resolveConfigModuleId(unresolved_id) {
if (unresolved_id !== "t18s-internal:config") return null;
return "\0t18s-internal:config";
}

/**
* @param {string} unresolved_id
* @returns {string | null}
*/
function resolveLoaderModuleId(unresolved_id) {
if (unresolved_id !== "t18s-internal:loaders") return null;
return "\0t18s-internal:loaders";
const [first, second] = filename.split(".");
if (!first) throw new Error(`Could not determine locale for ${path}`);
if (!second) throw new Error(`Could not determine domain for ${path}`);
return { locale: second, domain: first };
}
36 changes: 36 additions & 0 deletions packages/t18s/src/core/module-resolution/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* If the unresolved_id is for the t18s config, this function will resolve it.
* @type {import("./types.js").IDResolver}
*/
export const resolveConfigModuleId = (unresolved_id) => {
if (unresolved_id !== "t18s-internal:config") return null;
return "\0t18s-internal:config";
};

/**
* @type {import("./types.js").ModuleLoader}
*/
export const loadConfigModule = async (resolved_id, config, Catalogue) => {
if (resolved_id !== "\0t18s-internal:config") return null;
return generateConfigModule(config);
};

/** @type {string | null} */
let cachedCode = null;

/**
* @param {import("../types.js").ResolvedPluginConfig} config
*/
function generateConfigModule(config) {
if (cachedCode !== null) return cachedCode;
let code = "";
code += `export const verbose = ${config.verbose ? "true" : "false"};\n`;
code += `export const locales = ${JSON.stringify(config.locales)};\n`;
code += `export const fallbackLocale = ${
config.fallbackLocale ? `"${config.fallbackLocale}"` : "undefined"
};\n`;
code += `export const defaultDomain = "${config.defaultDomain}";\n`;
code += `export const loadingDelay = 200;\n`;
cachedCode = code;
return code;
}
35 changes: 35 additions & 0 deletions packages/t18s/src/core/module-resolution/dictionary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { MessageCatalogue } from "../MessageCatalogue.js";
import { generateDictionaryModule } from "../codegen/dictionary.js";

/**
* If the unresolved_id is for a t18s dictionary, this function will resolve it.
* Dictionary modules have the format "t18s-dictionary:<locale>:<domain>"
*
* @type {import("./types.js").IDResolver}
*/
export const resolveDictionaryModuleId = (unresolved_id) => {
if (!unresolved_id.startsWith("t18s-dictionary:")) return null;

const [_, locale, domain] = unresolved_id.split(":");
if (!locale || !domain) return null;

const resolved_id = "\0" + unresolved_id;
return resolved_id;
}

/**
* Returns the code for the dictionary module if the resolved_id is for the main module.
* @type {import("./types.js").ModuleLoader}
*/
export const loadDictionaryModule = async (resolved_id, config, Catalogue) => {
if (!resolved_id.startsWith("\0t18s-dictionary:")) return null;

const [_, locale, domain] = resolved_id.split(":");
if (!locale || !domain) return null;

const dictionary = Catalogue.getDictionary(locale, domain);

return dictionary
? generateDictionaryModule(dictionary)
: "export default {}";
}
17 changes: 17 additions & 0 deletions packages/t18s/src/core/module-resolution/loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { generateLoaderModule } from "../codegen/loaders.js";

/**
* @type {import("./types.js").ModuleLoader}
*/
export const loadLoaderModule = async (resolved_id, config, Catalogue) => {
if (resolved_id !== "\0t18s-internal:loaders") return null;
return generateLoaderModule(config, Catalogue);
};

/**
* @type {import("./types.js").IDResolver}
*/
export const resolveLoaderModuleId = (unresolved_id) => {
if (unresolved_id !== "t18s-internal:loaders") return null;
return "\0t18s-internal:loaders";
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { readFile } from "fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { normalizePath } from "vite";
Expand All @@ -12,11 +11,8 @@ function getT18SModulePath() {

const $t18sMainModulePath = getT18SModulePath();

/**
* @param {string} unresolved_id
* @returns {string | null}
*/
export function resolveMainModuleId(unresolved_id) {
/** @type {import("./types.js").IDResolver} */
export const resolveMainModuleId = (unresolved_id) => {
if (unresolved_id === VIRTUAL_MODULE_PREFIX) return $t18sMainModulePath;
return null;
}
};
5 changes: 5 additions & 0 deletions packages/t18s/src/core/module-resolution/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { MessageCatalogue } from "../MessageCatalogue.js"
import { ResolvedPluginConfig } from "../types.js"

export type ModuleLoader = (resolved_id: string, config: ResolvedPluginConfig, catalogue: MessageCatalogue) => Promise<string | null>;
export type IDResolver = (unresolved_id: string) => Promise<string | null> | string | null;
43 changes: 43 additions & 0 deletions packages/t18s/src/core/module-resolution/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { cleanUrl } from "../utils/id.js";

/**
* @param {import("./types.js").IDResolver[]} resolvers
* @returns {import("./types.js").IDResolver}
*/
export function resolveIdSequence(resolvers) {
return async (unresolved_id) => {
const id = cleanUrl(unresolved_id);

for (const resolver of resolvers) {
const resolved = resolver(id);
if (resolved) return resolved;
}

return null;
};
}

/**
* @param {import("./types.js").ModuleLoader[]} loaders
* @returns {import("./types.js").ModuleLoader}
*/
export function loadSequence(loaders) {
return async (resolved_id, config, Catalogue) => {
const id = cleanUrl(resolved_id);

//Attempt to load the module from all loaders
const loadingPromises = loaders.map((loader) =>
loader(id, config, Catalogue)
);
const results = await Promise.allSettled(loadingPromises);

//Pick the fulfilled result. There should only be one, otherwise we have a bug.
for (const result of results) {
if (result.status !== "fulfilled") continue;
if (result.value) return result.value;
}

//If none of the loaders could load the module, return null.
return null;
};
}
Loading

0 comments on commit feaf5f7

Please sign in to comment.