parse-features-string.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * Utilities to parse comma-separated key value pairs used in browser APIs.
  3. * For example: "x=100,y=200,width=500,height=500"
  4. */
  5. import { BrowserWindowConstructorOptions } from 'electron';
  6. type RequiredBrowserWindowConstructorOptions = Required<BrowserWindowConstructorOptions>;
  7. type IntegerBrowserWindowOptionKeys = {
  8. [K in keyof RequiredBrowserWindowConstructorOptions]:
  9. RequiredBrowserWindowConstructorOptions[K] extends number ? K : never
  10. }[keyof RequiredBrowserWindowConstructorOptions];
  11. // This could be an array of keys, but an object allows us to add a compile-time
  12. // check validating that we haven't added an integer property to
  13. // BrowserWindowConstructorOptions that this module doesn't know about.
  14. const keysOfTypeNumberCompileTimeCheck: { [K in IntegerBrowserWindowOptionKeys] : true } = {
  15. x: true,
  16. y: true,
  17. width: true,
  18. height: true,
  19. minWidth: true,
  20. maxWidth: true,
  21. minHeight: true,
  22. maxHeight: true,
  23. opacity: true
  24. };
  25. // Note `top` / `left` are special cases from the browser which we later convert
  26. // to y / x.
  27. const keysOfTypeNumber = ['top', 'left', ...Object.keys(keysOfTypeNumberCompileTimeCheck)];
  28. /**
  29. * Note that we only allow "0" and "1" boolean conversion when the type is known
  30. * not to be an integer.
  31. *
  32. * The coercion of yes/no/1/0 represents best effort accordance with the spec:
  33. * https://html.spec.whatwg.org/multipage/window-object.html#concept-window-open-features-parse-boolean
  34. */
  35. type CoercedValue = string | number | boolean;
  36. function coerce (key: string, value: string): CoercedValue {
  37. if (keysOfTypeNumber.includes(key)) {
  38. return parseInt(value, 10);
  39. }
  40. switch (value) {
  41. case 'true':
  42. case '1':
  43. case 'yes':
  44. case undefined:
  45. return true;
  46. case 'false':
  47. case '0':
  48. case 'no':
  49. return false;
  50. default:
  51. return value;
  52. }
  53. }
  54. export function parseCommaSeparatedKeyValue (source: string, useSoonToBeDeprecatedBehaviorForBareKeys: boolean) {
  55. const bareKeys = [] as string[];
  56. const parsed = {} as { [key: string]: any };
  57. for (const keyValuePair of source.split(',')) {
  58. const [key, value] = keyValuePair.split('=').map(str => str.trim());
  59. if (useSoonToBeDeprecatedBehaviorForBareKeys && value === undefined) {
  60. bareKeys.push(key);
  61. continue;
  62. }
  63. parsed[key] = coerce(key, value);
  64. }
  65. return { parsed, bareKeys };
  66. }
  67. export function parseWebViewWebPreferences (preferences: string) {
  68. return parseCommaSeparatedKeyValue(preferences, false).parsed;
  69. }
  70. const allowedWebPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'javascript', 'contextIsolation', 'webviewTag'] as const;
  71. type AllowedWebPreference = (typeof allowedWebPreferences)[number];
  72. /**
  73. * Parses a feature string that has the format used in window.open().
  74. *
  75. * `useSoonToBeDeprecatedBehaviorForBareKeys` — In the html spec, windowFeatures keys
  76. * without values are interpreted as `true`. Previous versions of Electron did
  77. * not respect this. In order to not break any applications, this will be
  78. * flipped in the next major version.
  79. */
  80. export function parseFeatures (
  81. features: string,
  82. useSoonToBeDeprecatedBehaviorForBareKeys: boolean = true
  83. ) {
  84. const { parsed, bareKeys } = parseCommaSeparatedKeyValue(features, useSoonToBeDeprecatedBehaviorForBareKeys);
  85. const webPreferences: { [K in AllowedWebPreference]?: any } = {};
  86. allowedWebPreferences.forEach((key) => {
  87. if (parsed[key] === undefined) return;
  88. webPreferences[key] = parsed[key];
  89. delete parsed[key];
  90. });
  91. if (parsed.left !== undefined) parsed.x = parsed.left;
  92. if (parsed.top !== undefined) parsed.y = parsed.top;
  93. return {
  94. options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'> & { [key: string]: CoercedValue },
  95. webPreferences,
  96. additionalFeatures: bareKeys
  97. };
  98. }