text: const cds = require('../cds'), cdsv = _emitting ( require('@sap/cds-compiler') )
  const { cdsc, sql_mapping } = cds.env,  _ = (...options) => Object.assign ({}, cdsc, ...options)
  
  // order of preference for hana backend transformation related options
  // 1. options passed via command line
  // 2. options defined in cds.env.cdsc.toHana
  // 3. options defined in cds.env.cdsc
  // 4. defaults defined here
  // 5. defaults defined in compiler
  const _hanaOpts = (o={}) => { return {toHana: Object.assign({}, cdsc.toHana, { csn: (o.csn !== undefined ? o.csn : cdsc.toHana && cdsc.toHana.csn !== undefined ? cdsc.toHana.csn : false), src: (o.src !== undefined ? o.src : cdsc.toHana && cdsc.toHana.src !== undefined ? cdsc.toHana.src : true), names: o.sql_mapping || cdsc.toHana && cdsc.toHana.names || sql_mapping }) }}
  const _hdiOpts = (o={}) => {return {toSql: Object.assign({}, cdsc.toSql, { src: 'hdi', dialect: 'hana', names: o.sql_mapping || cdsc.toSql && cdsc.toSql.names || sql_mapping })}}
  
  module.exports = {
    compile: (filenames, dir, o, _files) => cdsv.compile (filenames, dir,_(o), _files) .then (_csn4) .catch (e=>{ // NOSONAR
      if (e.errors) for (let any of e.errors) {
        if (/cds[/\\]common.cds/.test(any) && any.message.startsWith('Duplicate definition')) {
          // collect all distinct sources of duplicates
          const distinct = new Set
          for (let each of e.errors) {
            if (/cds[/\\]common.cds/.test (each.location.filename))  distinct.add (each.location.filename.slice(0,-10))
          }
          if (distinct.length > 1)  cds.error.duplicate_cds (...distinct)
        }
      }
      throw e
    }),
    parse: (sources,o) => _csn4 (cdsv.compileSources(sources, _(o))),
    parseCql: cdsv.parseToCqn,
    parseExpr: cdsv.parseToExpr,
    forOData: (csn,o) => _forODataOrSql (csn,cdsv.toOdata,o),
    forSql: (csn,o) => _forODataOrSql (csn,cdsv.toSql,o),
    toHana: (csn,o) => cdsv.toHana(_xsn4(csn),_(o, _hanaOpts(o))),
    toHdi: (csn,o) => cdsv.toSql(_xsn4(csn),_(o, _hdiOpts(o))),
    toCdl: (csn,o) => cdsv.toCdl(_xsn4(csn),_(o)),
    toSql: (csn,o) => cdsv.toSql(_xsn4(csn),_(o)),
    toSwagger: (csn,o) => cdsv.toSwagger (_xsn4(csn),_(o)),
    toOdata: (csn,o) => cdsv.toOdata (_xsn4(csn),_(o)),
    collectSources: (...args) => cdsv.collectSources(...args),
  }
  
  const _sql_names = cds._for_snapi_tests
  ? (o) => o && o.sql_mapping || sql_mapping !== 'plain' && sql_mapping
  : (o) => o && o.sql_mapping || sql_mapping
  
  const _forODataOrSql = (csn,fn,o) => {
    const xsn = fn(_xsn4(csn),_(o, { csn:true, names: _sql_names(o) }))
    const csnx = _csn4 (xsn._augmentedCsn, xsn.csn)
    return csnx
  }
  
  
  /** Returns a given model as plain csn.
   * The original augmented model is stored in the hidden property `_xsn`
   * @param model - an xsn or a csn
   * @param _csn - a raw compacted csn already obtained from cdsv
   */
  function _csn4 (model, _csn) {
  
    if (!('messages' in model))  return model  // not an xsn --> likely a csn
    if (!_csn && model._csn)  return model._csn  //> an xsn for which we already got a csn
  
    const csn={}, xsn=model
  
    // add/restore namespace of first source
    const first = xsn.sources [Object.keys(xsn.sources)[0]]
    const ns = first.namespace
    if (ns)  csn.namespace = ns.path ? ns.path.map(x => x.id).join('.') : ns
  
    // get csn for xsn from cdsv
    Object.assign (csn, _csn || cdsv.toCsn(xsn))
  
    // keep _sources and _xsn twin as hidden properties
    Object.defineProperties (csn, {
      _xsn: {value:xsn, configurable:1, writable:1 },
      _sources: {value: Object.keys (xsn.sources) },
    })
  
    // cache _csn to _xsn only in normalized models, i.e. not the flattened OData csn
    if (!_csn)  Object.defineProperty (xsn, '_csn', {value:csn, configurable:1, writable:1 })
  
    // forward support for Association to many smartly resolving their back links
    if (cdsc.smart.to_many)  require ('./2many')(csn)
  
    return csn
  }
  
  
  /** Returns a given model as an augmented one.
   * This is necessary because severel cdsv operations seem to always expect
   * augmented models created from own parser and don't work with plain CSNs
   * from other sources??
   */
  function _xsn4 (model) {
    // if (model._parsed)  model = model._parsed
    if (model.messages) return model   // it is already an augmented one
    if (model._xsn) return model._xsn   // came from cdsv before
    // doesn't stem from cdsv... (yes, this is all pretty crazy)
    let csn=model, xsn = cdsv.compileSources({'<dynamic csn>.json': JSON.stringify(csn, (k,v) => {
    //> fix: cdsv doesn't accept '.json' anymore
      if (k === 'namespace') return
      return v
    })})
    Object.defineProperty (csn, '_xsn', {value:xsn})
    Object.defineProperty (xsn, '_csn', {value:csn})
    return xsn
  }
  
  
  // Add .toString() support to cdsv's composite errors class
  // const { CompilationError } = require('@sap/cds-compiler/lib/base/messages')
  // const {inspect} = require('util')
  // Object.defineProperties (CompilationError.prototype, {
  //   [inspect.custom]: {value: function(){ return this.toString() }},
  //   toString: {value: function(){
  //     return 'cds.compile failed due to these errors...\n\n'+
  //      (this.errors ? this.errors.reduce((p,e) => p + (
  //       e.location ? (' at '+e) //.replace (': Error: ',': ')
  //         .replace ('Extraneous input','invalid token')
  //         .replace(/ expecting {(<EOF>, )?([^}]*)}/, (str,_,p1) => ` - expected one of `+ p1.toLowerCase() + '.')
  //       : e
  //     ) + '\n', '') : this)
  //   }}
  // })
  
  // Need to propagate compiler warnings and infos in absence of errors.
  // Decorate all cdsv functions with one that emits messages after it was called
  //
  // TODO REVISIT: performance impact?  modularity?
  function _emitting (cdsv) { // NOSONAR
    const emitter = {}
    for (let p of Reflect.ownKeys(cdsv)) {
      let v = Reflect.getOwnPropertyDescriptor(cdsv, p).value
      if (typeof v === 'function') {
        emitter[p] = (x,o,o2,...etc) => {
          const r = cdsv[p] (x,o,o2,...etc), messages = o && o._messages || o2 && o2._messages
          if (messages)  return (r instanceof Promise) ? r.then (r => _emit(r,messages)) : _emit (r,messages)
          else  return r
        }
      } else { emitter[p] = v }
    }
    return emitter
  }
  
  function _emit (x,messages) {
    if (Array.isArray (x.messages)) {
      x.messages.forEach (m => messages.push (m))
    }
    return x
  }
  