1// Copyright 2022 Google LLC
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7//     http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.import { exec } from 'child_process';
14
15import DOM, { INewTag, IUpdateTag } from './DOMFuncs';
16import { FileIO } from './FileIO';
17import { IMigItem, IMigrationMap } from './migrationList';
18
19export type TResultExistingEval = ['update' | 'duplicate', IUpdateTag] | void;
20export type TResultMissingEval = INewTag | void;
21
22interface IProcessXML {
23    attr?: string;
24    containerQuery?: string;
25    evalExistingEntry?: TEvalExistingEntry;
26    evalMissingEntry?: TEvalMissingEntry;
27    hidable?: boolean;
28    path: string;
29    step: number;
30    tagName: string;
31}
32
33export type TEvalExistingEntry = (
34    attrname: string,
35    migItem: IMigItem,
36    qItem: Element
37) => TResultExistingEval;
38
39export type TEvalMissingEntry = (originalToken: string, migItem: IMigItem) => TResultMissingEval;
40
41export async function processQueriedEntries(
42    migrationMap: IMigrationMap,
43    {
44        attr = 'name',
45        containerQuery = '*',
46        evalExistingEntry,
47        path,
48        step,
49        tagName,
50        evalMissingEntry,
51    }: IProcessXML
52) {
53    const doc = await FileIO.loadXML(path);
54
55    const containerElement =
56        (containerQuery && doc.querySelector(containerQuery)) || doc.documentElement;
57
58    migrationMap.forEach((migItem, originalToken) => {
59        migItem.step[step] = 'ignore';
60
61        const queryTiems = containerElement.querySelectorAll(
62            `${tagName}[${attr}="${originalToken}"]`
63        );
64
65        if (evalMissingEntry) {
66            const addinOptions = evalMissingEntry(originalToken, migItem);
67
68            if (queryTiems.length == 0 && containerElement && addinOptions) {
69                DOM.addEntry(containerElement, addinOptions);
70                migItem.step[step] = 'add';
71                return;
72            }
73        }
74
75        if (evalExistingEntry)
76            queryTiems.forEach((qEl) => {
77                const attrName = qEl.getAttribute(attr);
78                const migItem = migrationMap.get(attrName || '');
79
80                if (!attrName || !migItem) return;
81
82                const updateOptions = evalExistingEntry(attrName, migItem, qEl);
83
84                if (!updateOptions) return;
85
86                const [processType, processOptions] = updateOptions;
87
88                switch (processType) {
89                    case 'update':
90                        if (DOM.updateElement(qEl, processOptions)) migItem.step[step] = 'update';
91                        break;
92
93                    case 'duplicate':
94                        if (DOM.duplicateEntryWithChange(qEl, processOptions))
95                            migItem.step[step] = 'duplicate';
96                        break;
97                }
98            });
99    });
100
101    await FileIO.saveFile(doc.documentElement.outerHTML, path);
102}
103