Legacy wallets used the "keypool" model which stored a bunch of keys. See src/wallet/scriptbpubkeyman.h#L52-L100 for historical context on the "keypool" model.
The wallet would then simply iterate over each public key and generate a scriptPubKey (a.k.a. PubKey script) and address for each type of script the wallet supported. However this approach has a number of shortcomings (from least to most important):
One key could have multiple addresses
It was difficult to sign for multisig
Adding new script functionality required adding new hardcoded script types into the wallet code for each new type of script.
Such an approach was not scalable in the long term and so a new format of wallet needed to be introduced.
Descriptor wallets instead store output script "descriptors". These descriptors can be of any valid script type, including arbitrary scripts which might be "unknown" to the wallet software, and this means that wallets can deterministically generate addresses for any type of valid descriptor provided by the user.
Descriptors not only contain what is needed to generate an address, they also include all the script template data needed to "solve" (i.e. spend) outputs received at them. In other words they permit a valid
witnessScript) to be generated. The document Support for Output Descriptors in Bitcoin Core provides more details and examples of these output descriptors.