Skip to content

Commit

Permalink
fix(Types): fix race condition in loading types
Browse files Browse the repository at this point in the history
  • Loading branch information
hatemhosny committed Jan 21, 2024
1 parent cc7761d commit a85ba31
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 15 deletions.
14 changes: 10 additions & 4 deletions src/livecodes/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,12 @@ const createIframe = (container: HTMLElement, result = '', service = sandboxServ
resultLanguages = getEditorLanguages();
});

const loadModuleTypes = async (editors: Editors, config: Config, force = false) => {
const loadModuleTypes = async (
editors: Editors,
config: Config,
loadAll = false,
force = false,
) => {
if (typeof editors?.script?.addTypes !== 'function') return;
const scriptLanguage = config.script.language;
if (['typescript', 'javascript'].includes(mapLanguage(scriptLanguage)) || force) {
Expand All @@ -327,6 +332,7 @@ const loadModuleTypes = async (editors: Editors, config: Config, force = false)
const libs = await typeLoader.load(
getConfig().script.content + '\n' + getConfig().markup.content,
configTypes,
loadAll,
force,
);
libs.forEach((lib) => editors.script.addTypes?.(lib, force));
Expand Down Expand Up @@ -729,7 +735,7 @@ const changeLanguage = async (language: Language, value?: string, isUpdate = fal
await setSavedStatus();
dispatchChangeEvent();
addConsoleInputCodeCompletion();
loadModuleTypes(editors, getConfig());
loadModuleTypes(editors, getConfig(), /* loadAll = */ true);
await applyLanguageConfigs(language);
};

Expand Down Expand Up @@ -3458,7 +3464,7 @@ const handleCustomSettings = () => {
setCustomSettingsMark();
await setSavedStatus();
if (customSettings.types) {
loadModuleTypes(editors, getConfig(), /* force */ true);
loadModuleTypes(editors, getConfig(), /* loadAll = */ true, /* force */ true);
}
}
customSettingsEditor?.destroy();
Expand Down Expand Up @@ -4149,7 +4155,7 @@ const bootstrap = async (reload = false) => {
setExternalResourcesMark();
setCustomSettingsMark();
updateCompiledCode();
loadModuleTypes(editors, getConfig());
loadModuleTypes(editors, getConfig(), /* loadAll = */ true);
compiler.load(Object.values(editorLanguages || {}), getConfig()).then(() => {
if (!getConfig().autoupdate) {
setLoading(false);
Expand Down
4 changes: 1 addition & 3 deletions src/livecodes/types/default-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@ import type { Types } from '../models';
import { modulesService } from '../services/modules';

export const getDefaultTypes = (): Types => ({
react: modulesService.getUrl('@types/react/index.d.ts'),
'react-dom': modulesService.getUrl('@types/react-dom/index.d.ts'),
'react-dom/client': modulesService.getUrl('@types/react-dom/client.d.ts'),
livecodes: modulesService.getUrl('livecodes/livecodes.d.ts'),
});
24 changes: 16 additions & 8 deletions src/livecodes/types/type-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
import type { EditorLibrary, Types } from '../models';
import { getImports, hasUrlImportsOrExports } from '../compiler/import-map';
import { typesService } from '../services/types';
import { objectFilter, removeDuplicates, safeName } from '../utils/utils';
import { objectFilter, safeName } from '../utils/utils';

export const createTypeLoader = (baseUrl: string) => {
let loadedTypes: Types = {};
const libs: EditorLibrary[] = [];

const getTypeContents = async (type: Types): Promise<EditorLibrary> => {
let content = '';
const name = Object.keys(type)[0];
const value = Object.values(type)[0];
const url = typeof value === 'string' ? value : value.url;

if (loadedTypes[name]) {
return { filename: '', content: '' };
}
if (url) {
try {
const res = await fetch(url);
Expand Down Expand Up @@ -46,19 +49,23 @@ export const createTypeLoader = (baseUrl: string) => {
}),
{},
);
if (content.trim() === '') {
loadedTypes = prevTypes;
return { filename: '', content: '' };
}
loadedTypes = { ...prevTypes, ...type };
return {
const lib = {
filename: `file:///node_modules/${safeName(name)}/index.d.ts`,
content,
};
libs.push(lib);
return lib;
};

const loadTypes = (types: Types) =>
Promise.all(
removeDuplicates(Object.keys(types)).map((t) => getTypeContents({ [t]: types[t] })),
);
Promise.all(Object.keys(types).map((t) => getTypeContents({ [t]: types[t] })));

const load = async (code: string, configTypes: Types, forceLoad = false) => {
const load = async (code: string, configTypes: Types, loadAll = false, forceLoad = false) => {
const imports = getImports(code);

const codeTypes: Types = imports.reduce((accTypes, lib) => {
Expand Down Expand Up @@ -101,7 +108,8 @@ export const createTypeLoader = (baseUrl: string) => {
value.autoload === true,
);

return loadTypes({ ...codeTypes, ...fetchedTypes, ...autoloadTypes });
const newLibs = await loadTypes({ ...codeTypes, ...fetchedTypes, ...autoloadTypes });
return loadAll ? libs : newLibs;
};

return {
Expand Down

0 comments on commit a85ba31

Please sign in to comment.