libmodulor
Version:
A TypeScript library to create platform-agnostic applications
78 lines (77 loc) • 3.14 kB
JavaScript
import { UC_MAIN_SERVER_SUFFIX } from '../../convention.js';
const CORE_SERVER_MAINS = ['IdleServerMain'];
const TOKEN_IMPORT = 'import';
const TOKEN_IMPORT_END = ';';
const TOKEN_LIFECYCLE_SERVER = 'server: {';
const TOKEN_LIFECYCLE_SERVER_END = '},';
const TOKEN_LIFECYCLE_SERVER_REPLACE = 'server: true,';
/**
* Strip the server part of the UCD
*
* To be used by bundlers when building for the web for example, or any other clients (e.g. React Native).
*
* WARNING : This implementation is very naive and will have unexpected behaviors when the UCD has a specific shape.
* For instance, if there is another `server: {` occurence than the lifecycle.server definition, it will be wrongly replaced.
*
* TODO : Make this implementation more robust (let's try not to use an AST parser though, to keep things fast and simple).
*
* @param source
* @returns
*/
export function stripUCDLifecycleServer(source) {
const occurrences = [
...source.matchAll(new RegExp(UC_MAIN_SERVER_SUFFIX, 'g')),
];
const count = occurrences.length;
const toReplace = [];
let occIdx = 0;
for (const occ of occurrences) {
if (count === 3 && occIdx === 1) {
// Skip the 2nd occurrence as it is part of the import of the 1st (Rrrrh very hacky...)
occIdx += 1;
continue;
}
const toRep = { end: 0, start: 0, str: '' };
let cursor = occ.index;
let expr = '';
while (!expr.startsWith(TOKEN_IMPORT) &&
!expr.startsWith(TOKEN_LIFECYCLE_SERVER)) {
expr = `${source[cursor]}${expr}`;
cursor -= 1;
}
toRep.start = cursor;
cursor = occ.index;
while (!expr.endsWith(TOKEN_IMPORT_END) &&
!expr.endsWith(TOKEN_LIFECYCLE_SERVER_END)) {
expr = `${expr}${source[cursor]}`;
cursor += 1;
}
toRep.end = cursor;
toRep.str = source.substring(toRep.start, toRep.end).trim();
toReplace.push(toRep);
occIdx += 1;
}
// Flip the items to replace in order to remove the usage before the imports
// This is related to the edge case of IdleServerMain that we remove from the imports list,
// while for specific ServerMain, we remove the entire import instruction.
toReplace.reverse();
let cleaned = source;
for (const { str } of toReplace) {
if (str.startsWith(TOKEN_LIFECYCLE_SERVER)) {
cleaned = cleaned.replaceAll(str, TOKEN_LIFECYCLE_SERVER_REPLACE);
continue;
}
if (str.startsWith(TOKEN_IMPORT)) {
for (const coreServerMain of CORE_SERVER_MAINS) {
if (str.includes(coreServerMain)) {
cleaned = cleaned.replace(new RegExp(`${coreServerMain},?`), '');
}
}
cleaned = cleaned.replaceAll(str, '');
}
}
if (cleaned.includes(UC_MAIN_SERVER_SUFFIX)) {
throw new Error(`Stripping UCD server lifecycle did not complete successfully. The output still contains references to ${UC_MAIN_SERVER_SUFFIX} : ${cleaned}`);
}
return cleaned;
}