modes.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import { copyObj, createObj } from "./util/misc.js"
  2. // Known modes, by name and by MIME
  3. export let modes = {}, mimeModes = {}
  4. // Extra arguments are stored as the mode's dependencies, which is
  5. // used by (legacy) mechanisms like loadmode.js to automatically
  6. // load a mode. (Preferred mechanism is the require/define calls.)
  7. export function defineMode(name, mode) {
  8. if (arguments.length > 2)
  9. mode.dependencies = Array.prototype.slice.call(arguments, 2)
  10. modes[name] = mode
  11. }
  12. export function defineMIME(mime, spec) {
  13. mimeModes[mime] = spec
  14. }
  15. // Given a MIME type, a {name, ...options} config object, or a name
  16. // string, return a mode config object.
  17. export function resolveMode(spec) {
  18. if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
  19. spec = mimeModes[spec]
  20. } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
  21. let found = mimeModes[spec.name]
  22. if (typeof found == "string") found = {name: found}
  23. spec = createObj(found, spec)
  24. spec.name = found.name
  25. } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
  26. return resolveMode("application/xml")
  27. } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
  28. return resolveMode("application/json")
  29. }
  30. if (typeof spec == "string") return {name: spec}
  31. else return spec || {name: "null"}
  32. }
  33. // Given a mode spec (anything that resolveMode accepts), find and
  34. // initialize an actual mode object.
  35. export function getMode(options, spec) {
  36. spec = resolveMode(spec)
  37. let mfactory = modes[spec.name]
  38. if (!mfactory) return getMode(options, "text/plain")
  39. let modeObj = mfactory(options, spec)
  40. if (modeExtensions.hasOwnProperty(spec.name)) {
  41. let exts = modeExtensions[spec.name]
  42. for (let prop in exts) {
  43. if (!exts.hasOwnProperty(prop)) continue
  44. if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]
  45. modeObj[prop] = exts[prop]
  46. }
  47. }
  48. modeObj.name = spec.name
  49. if (spec.helperType) modeObj.helperType = spec.helperType
  50. if (spec.modeProps) for (let prop in spec.modeProps)
  51. modeObj[prop] = spec.modeProps[prop]
  52. return modeObj
  53. }
  54. // This can be used to attach properties to mode objects from
  55. // outside the actual mode definition.
  56. export let modeExtensions = {}
  57. export function extendMode(mode, properties) {
  58. let exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {})
  59. copyObj(properties, exts)
  60. }
  61. export function copyState(mode, state) {
  62. if (state === true) return state
  63. if (mode.copyState) return mode.copyState(state)
  64. let nstate = {}
  65. for (let n in state) {
  66. let val = state[n]
  67. if (val instanceof Array) val = val.concat([])
  68. nstate[n] = val
  69. }
  70. return nstate
  71. }
  72. // Given a mode and a state (for that mode), find the inner mode and
  73. // state at the position that the state refers to.
  74. export function innerMode(mode, state) {
  75. let info
  76. while (mode.innerMode) {
  77. info = mode.innerMode(state)
  78. if (!info || info.mode == mode) break
  79. state = info.state
  80. mode = info.mode
  81. }
  82. return info || {mode: mode, state: state}
  83. }
  84. export function startState(mode, a1, a2) {
  85. return mode.startState ? mode.startState(a1, a2) : true
  86. }