All files / src/types/kps kps-file-reader.ts

92.68% Statements 76/82
75% Branches 9/12
100% Functions 4/4
92.68% Lines 76/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 831x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x 1x 4x 4x 4x 4x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x         3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 15x     15x 3x 3x 3x 3x 3x  
/*
 * Keyman is copyright (C) SIL Global. MIT License.
 *
 * Created by mcdurdin on 2024-10-16
 *
 * XML reader for .kps file format
 */
 
import { util } from '@keymanapp/common-types';
import boxXmlArray = util.boxXmlArray;
 
import { CommonTypesMessages } from "../../common-messages.js";
import { CompilerCallbacks } from "../../compiler-callbacks.js";
import { KeymanXMLReader } from "../../xml-utils.js";
import { KpsPackage } from "./kps-file.js";
 
export class KpsFileReader {
  constructor(private callbacks: CompilerCallbacks) {
 
  }
 
  public read(file: Uint8Array): KpsPackage {
    const data = new TextDecoder().decode(file);
 
    const kpsPackage = (() => {
        let a: KpsPackage;
 
        try {
          a = new KeymanXMLReader('kps')
            .parse(data) as KpsPackage;
        } catch(e) {
          this.callbacks.reportMessage(CommonTypesMessages.Error_InvalidPackageFile({e}));
        }
        return a;
    })();
 
    if(!kpsPackage) {
      return null;
    }
 
    return this.boxArrays(kpsPackage);
  }
 
  private boxArrays(data: KpsPackage): KpsPackage {
    boxXmlArray(data.Package?.Files, 'File');
    boxXmlArray(data.Package?.Keyboards, 'Keyboard');
    boxXmlArray(data.Package?.LexicalModels, 'LexicalModel');
    boxXmlArray(data.Package?.RelatedPackages, 'RelatedPackage');
 
    if(data.Package?.Keyboards?.Keyboard) {
      for(const k of data.Package.Keyboards.Keyboard) {
        boxXmlArray(k.Examples, 'Example');
        boxXmlArray(k.Languages, 'Language');
        boxXmlArray(k.WebDisplayFonts, 'Font');
        boxXmlArray(k.WebOSKFonts, 'Font');
      }
    }
 
    if(data.Package?.LexicalModels?.LexicalModel) {
      for(const lm of data.Package.LexicalModels.LexicalModel) {
        boxXmlArray(lm.Languages, 'Language');
      }
    }
 
    boxXmlArray(data.Package?.RelatedPackages, 'RelatedPackage');
    boxXmlArray(data.Package?.StartMenu?.Items, 'Item');
    boxXmlArray(data.Package?.Strings, 'String');
 
    if(data.Package?.Info) {
      // If no properties are defined on an <Info> subitem, then it will be a
      // string, and needs to be boxed into a KpsInfoItem object
      const info: any = data.Package.Info;
      for(const k of Object.keys(info)) {
        if(typeof info[k] == 'string') {
          info[k] = { _: info[k], $: { URL: '' } };
        }
      }
    }
 
    return data;
  }
};