aboutsummaryrefslogblamecommitdiff
path: root/src/shared/SettingData.ts
blob: 0d72874ef5446808c4db46152b04da079f287634 (plain) (tree)
1
2
3
4
5
6
7
8
9




                                                                       
                          
                                                  
 
                                                       

                     
                        
                                                                
                                             


                                  
                                  
                                                           
                                     
   
                                      


                                                            
                     




                                    
                                                                      
                                      



                                 
                                                     
                                  
                                              
                                          
                                   
 
                      
                                         
                                           






                                 
                                   
 
                                       




                                                           
                              
                                                   

                                             



                        
     




                            
                                                                    
                                                     
                                                              



                                                     
                                                 
                                                          
                                       

        
                                                         

   
                               
                                      
                          
                                                    
   
                        

                     
                                                
   
                                                         
                  




                                                                    


                           
                                       
 
                                     
 
                                         
 
                                       


                         
                           
                        










                                                        
                    






                                                     
                    

      
                                                        
                                                                              
   
                                                          


                            
               


                          
                              
                                                 
                                                      
                                           
                                         


             



                                                 

                                     
                                           
                                         

      
                                                                          



                                                           
                                      
                                        
                                     






                                                     
                    


                           
                



                                  
                                  


                              

           
      

                            








                              
                               
                     
                                                   




                           
                                                   




                          








                                                             




                                                               


                                           


                                                               
                      
                   
                                              
                       












                                                                



                                                            
                                                                     
                 
                               
   
import * as operations from "./operations";
import Settings, { DefaultSettingJSONText } from "./settings/Settings";
import Keymaps from "./settings/Keymaps";
import Search from "./settings/Search";
import Properties from "./settings/Properties";
import Blacklist from "./settings/Blacklist";

export class FormKeymaps {
  private readonly data: { [op: string]: string };

  private constructor(data: { [op: string]: string }) {
    this.data = data;
  }

  toKeymaps(): Keymaps {
    const keymaps: { [key: string]: operations.Operation } = {};
    for (const name of Object.keys(this.data)) {
      const [type, argStr] = name.split("?");
      let args = {};
      if (argStr) {
        args = JSON.parse(argStr);
      }
      const key = this.data[name];
      keymaps[key] = operations.valueOf({ type, ...args });
    }
    return Keymaps.fromJSON(keymaps);
  }

  toJSON(): { [op: string]: string } {
    return this.data;
  }

  buildWithOverride(op: string, keys: string): FormKeymaps {
    const newData = {
      ...this.data,
      [op]: keys,
    };
    return new FormKeymaps(newData);
  }

  static fromJSON(o: ReturnType<FormKeymaps["toJSON"]>): FormKeymaps {
    const data: { [op: string]: string } = {};
    for (const op of Object.keys(o)) {
      data[op] = o[op] as string;
    }
    return new FormKeymaps(data);
  }

  static fromKeymaps(keymaps: Keymaps): FormKeymaps {
    const json = keymaps.toJSON();
    const data: { [op: string]: string } = {};
    for (const key of Object.keys(json)) {
      const op = json[key];
      const { type, ...args } = op;

      let name = type;
      if (Object.keys(args).length > 0) {
        name += "?" + JSON.stringify(args);
      }
      data[name] = key;
    }
    return new FormKeymaps(data);
  }
}

export class FormSearch {
  private readonly default: string;

  private readonly engines: string[][];

  constructor(defaultEngine: string, engines: string[][]) {
    this.default = defaultEngine;
    this.engines = engines;
  }

  toSearchSettings(): Search {
    const engines: { [name: string]: string } = {};
    for (const entry of this.engines) {
      engines[entry[0]] = entry[1];
    }
    return new Search(this.default, engines);
  }

  toJSON(): {
    default: string;
    engines: string[][];
  } {
    return {
      default: this.default,
      engines: this.engines,
    };
  }

  static fromJSON(o: ReturnType<FormSearch["toJSON"]>): FormSearch {
    if (!Object.prototype.hasOwnProperty.call(o, "default")) {
      throw new TypeError(`"default" field not set`);
    }
    if (!Object.prototype.hasOwnProperty.call(o, "engines")) {
      throw new TypeError(`"engines" field not set`);
    }
    return new FormSearch(o.default, o.engines);
  }

  static fromSearch(search: Search): FormSearch {
    const engines = Object.entries(search.engines).reduce(
      (o: string[][], [name, url]) => {
        return o.concat([[name, url]]);
      },
      []
    );
    return new FormSearch(search.defaultEngine, engines);
  }
}

export class JSONTextSettings {
  constructor(private json: string) {}

  toSettings(): Settings {
    return Settings.fromJSON(JSON.parse(this.json));
  }

  toJSONText(): string {
    return this.json;
  }

  static fromText(o: string): JSONTextSettings {
    return new JSONTextSettings(o);
  }

  static fromSettings(data: Settings): JSONTextSettings {
    const json = {
      keymaps: data.keymaps.toJSON(),
      search: data.search,
      properties: data.properties,
      blacklist: data.blacklist,
    };
    return new JSONTextSettings(JSON.stringify(json, undefined, 2));
  }
}

export class FormSettings {
  public readonly keymaps: FormKeymaps;

  public readonly search: FormSearch;

  public readonly properties: Properties;

  public readonly blacklist: Blacklist;

  constructor(
    keymaps: FormKeymaps,
    search: FormSearch,
    properties: Properties,
    blacklist: Blacklist
  ) {
    this.keymaps = keymaps;
    this.search = search;
    this.properties = properties;
    this.blacklist = blacklist;
  }

  buildWithKeymaps(keymaps: FormKeymaps): FormSettings {
    return new FormSettings(
      keymaps,
      this.search,
      this.properties,
      this.blacklist
    );
  }

  buildWithSearch(search: FormSearch): FormSettings {
    return new FormSettings(
      this.keymaps,
      search,
      this.properties,
      this.blacklist
    );
  }

  buildWithProperties(props: Properties): FormSettings {
    return new FormSettings(this.keymaps, this.search, props, this.blacklist);
  }

  buildWithBlacklist(blacklist: Blacklist): FormSettings {
    return new FormSettings(
      this.keymaps,
      this.search,
      this.properties,
      blacklist
    );
  }

  toSettings(): Settings {
    return Settings.fromJSON({
      keymaps: this.keymaps.toKeymaps().toJSON(),
      search: this.search.toSearchSettings().toJSON(),
      properties: this.properties.toJSON(),
      blacklist: this.blacklist.toJSON(),
    });
  }

  toJSON(): {
    keymaps: ReturnType<FormKeymaps["toJSON"]>;
    search: ReturnType<FormSearch["toJSON"]>;
    properties: ReturnType<Properties["toJSON"]>;
    blacklist: ReturnType<Blacklist["toJSON"]>;
  } {
    return {
      keymaps: this.keymaps.toJSON(),
      search: this.search.toJSON(),
      properties: this.properties.toJSON(),
      blacklist: this.blacklist.toJSON(),
    };
  }

  static fromJSON(o: ReturnType<FormSettings["toJSON"]>): FormSettings {
    for (const name of ["keymaps", "search", "properties", "blacklist"]) {
      if (!Object.prototype.hasOwnProperty.call(o, name)) {
        throw new Error(`"${name}" field not set`);
      }
    }
    return new FormSettings(
      FormKeymaps.fromJSON(o.keymaps),
      FormSearch.fromJSON(o.search),
      Properties.fromJSON(o.properties),
      Blacklist.fromJSON(o.blacklist)
    );
  }

  static fromSettings(data: Settings): FormSettings {
    return new FormSettings(
      FormKeymaps.fromKeymaps(data.keymaps),
      FormSearch.fromSearch(data.search),
      data.properties,
      data.blacklist
    );
  }
}

export enum SettingSource {
  JSON = "json",
  Form = "form",
}

export default class SettingData {
  private source: SettingSource;

  private json?: JSONTextSettings;

  private form?: FormSettings;

  constructor({
    source,
    json,
    form,
  }: {
    source: SettingSource;
    json?: JSONTextSettings;
    form?: FormSettings;
  }) {
    this.source = source;
    this.json = json;
    this.form = form;
  }

  getSource(): SettingSource {
    return this.source;
  }

  getJSON(): JSONTextSettings {
    if (!this.json) {
      throw new TypeError("json settings not set");
    }
    return this.json;
  }

  getForm(): FormSettings {
    if (!this.form) {
      throw new TypeError("form settings not set");
    }
    return this.form;
  }

  toJSON(): any {
    switch (this.source) {
      case SettingSource.JSON:
        return {
          source: this.source,
          json: (this.json as JSONTextSettings).toJSONText(),
        };
      case SettingSource.Form:
        return {
          source: this.source,
          form: (this.form as FormSettings).toJSON(),
        };
    }
    throw new Error(`unknown settings source: ${this.source}`);
  }

  toSettings(): Settings {
    switch (this.source) {
      case SettingSource.JSON:
        return this.getJSON().toSettings();
      case SettingSource.Form:
        return this.getForm().toSettings();
    }
    throw new Error(`unknown settings source: ${this.source}`);
  }

  static fromJSON(o: {
    source: string;
    json?: string;
    form?: ReturnType<FormSettings["toJSON"]>;
  }): SettingData {
    switch (o.source) {
      case SettingSource.JSON:
        return new SettingData({
          source: o.source,
          json: JSONTextSettings.fromText(
            o.json as ReturnType<JSONTextSettings["toJSONText"]>
          ),
        });
      case SettingSource.Form:
        return new SettingData({
          source: o.source,
          form: FormSettings.fromJSON(
            o.form as ReturnType<FormSettings["toJSON"]>
          ),
        });
    }
    throw new Error(`unknown settings source: ${o.source}`);
  }
}

export const DefaultSettingData: SettingData = SettingData.fromJSON({
  source: "json",
  json: DefaultSettingJSONText,
});