constructor (config, parser) {
        this.__config = config;
        this.__meta = {};
        
        this.__currentModuleId = null;
        this.__currentMapChain = null;
        this.__currentOriginalCode = null;
        this.__currentLoadQueue = [];
        this.__parser = parser;
        this.__errorState = true;

        this.__onAddWatchFile = (source, parent) => {};
        this.__onGetWatchFiles = () => ([]);
        this.__onEmitFile = (referenceId, emittedFile) => {};
        this.__onGetFileName = (referenceId) => '';
        this.__onGetModuleIds = () => new Set().values();
        this.__onGetModuleInfo = (id) => ({});
        this.__onSetAssetSource = (id, source) => {};
        this.__onLoad = (resolvedId) => Promise.resolve();
        
        this.__errorHandler = new PluginErrorHandler();
        this.__errorHandler.onThrow(() => {
            this.__errorState = true;
        });

        this.__plugins = (config.plugins || []).map(plugin => ({
            execute: plugin,
            context: PluginContext.create(this, plugin),
            error: this.__errorHandler
        }));

        this.hooks = /** @type {PluginLifecycleHooks} */ (Object.entries(PluginLifecycle.create(this)).reduce((acc, val) => {
            if (val[0] === 'buildEnd' || val[0] === 'renderError' || val[0] === 'watchChange') {
                acc[val[0]] = val[1];
                return acc;
            }

            acc[val[0]] = (...args) => {
                if (this.__errorState) {
                    throw new Error('PluginContainer "start()" method must be called before going further.');
                }

                // @ts-ignore
                return val[1](...args);
            }

            return acc;
        }, {}));
    }
@param {RollupConfigContainer} config 
@param {{parse: function(string, object): ESTree}} parser