import webpack from "webpack";

import type { Compiler, javascript } from "webpack";

const { WebpackError } = webpack;

class AvoidStandaloneProcessEnvMemberExpression {
    private plugin = "AvoidStandaloneProcessEnvMemberExpression";

    public apply(compiler: Compiler) {
        const { plugin } = this;

        compiler.hooks.thisCompilation.tap(plugin, (compilation, { normalModuleFactory }) => {
            const handler = (parser: javascript.JavascriptParser) => {
                parser.hooks.expression.for("process.env").tap(plugin, (expression) => {
                    const { type, object, property } = expression as any;
                    const { resource } = parser.state.module;
                    if (
                        resource.indexOf("/node_modules/") === -1 &&
                        type === "MemberExpression" &&
                        object?.type === "Identifier" &&
                        property?.type === "Identifier" &&
                        object.name === "process" &&
                        property.name === "env" &&
                        // Filter out false-positives with nested member expressions
                        // eslint-disable-next-line no-useless-escape
                        /process\.env[^\.\?]/.test(parser.state.source.toString())
                    ) {
                        compilation.errors.push(
                            new WebpackError(
                                `${this.plugin}: Member expression 'process.env' without identifier found. Use 'process.env.MY_VAR' instead and do not use key 'process.env' in DefinePlugin to avoid exposing the complete environment: ${resource}`,
                            ),
                        );
                    }
                });
            };

            normalModuleFactory.hooks.parser.for("javascript/dynamic").tap(plugin, handler);
            normalModuleFactory.hooks.parser.for("javascript/auto").tap(plugin, handler);
            normalModuleFactory.hooks.parser.for("javascript/esm").tap(plugin, handler);
        });
    }
}

export { AvoidStandaloneProcessEnvMemberExpression };
