241 lines
8.3 KiB
TypeScript
241 lines
8.3 KiB
TypeScript
// Copyright 2022 Google LLC
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.import { exec } from 'child_process';
|
|
|
|
import DOM from './helpers/DOMFuncs';
|
|
import { FileIO } from './helpers/FileIO';
|
|
import { loadMIgrationList } from './helpers/migrationList';
|
|
import { processQueriedEntries, TEvalExistingEntry } from './helpers/processXML';
|
|
import { repoPath } from './helpers/rootPath';
|
|
import { groupReplace } from './helpers/textFuncs';
|
|
|
|
async function init() {
|
|
const migrationMap = await loadMIgrationList();
|
|
const basePath = `${repoPath}/../tm-qpr-dev/frameworks/base/core/res/res/values/`;
|
|
|
|
await processQueriedEntries(migrationMap, {
|
|
containerQuery: 'declare-styleable[name="Theme"]',
|
|
hidable: true,
|
|
path: `${basePath}attrs.xml`,
|
|
step: 0,
|
|
tagName: 'attr',
|
|
evalExistingEntry: (_attrValue, migItem, qItem) => {
|
|
const { hidden, textContent: currentComment } = DOM.getElementComment(qItem);
|
|
|
|
if (hidden) migItem.isHidden = hidden;
|
|
|
|
const { newComment } = migItem;
|
|
return [
|
|
hidden ? 'update' : 'duplicate',
|
|
{
|
|
attrs: { name: migItem.replaceToken },
|
|
...(newComment
|
|
? { comment: `${newComment} @hide ` }
|
|
: currentComment
|
|
? { comment: hidden ? currentComment : `${currentComment} @hide ` }
|
|
: {}),
|
|
},
|
|
];
|
|
},
|
|
evalMissingEntry: (_originalToken, { replaceToken, newComment }) => {
|
|
return {
|
|
tagName: 'attr',
|
|
attrs: {
|
|
name: replaceToken,
|
|
format: 'color',
|
|
},
|
|
comment: `${newComment} @hide `,
|
|
};
|
|
},
|
|
});
|
|
|
|
// only update all existing entries
|
|
await processQueriedEntries(migrationMap, {
|
|
tagName: 'item',
|
|
path: `${basePath}themes_device_defaults.xml`,
|
|
containerQuery: 'resources',
|
|
step: 2,
|
|
evalExistingEntry: (_attrValue, { isHidden, replaceToken, step }, _qItem) => {
|
|
if (step[0] != 'ignore')
|
|
return [
|
|
isHidden ? 'update' : 'duplicate',
|
|
{
|
|
attrs: { name: replaceToken },
|
|
},
|
|
];
|
|
},
|
|
});
|
|
|
|
// add missing entries on specific container
|
|
await processQueriedEntries(migrationMap, {
|
|
tagName: 'item',
|
|
path: `${basePath}themes_device_defaults.xml`,
|
|
containerQuery: 'resources style[parent="Theme.Material"]',
|
|
step: 3,
|
|
evalMissingEntry: (originalToken, { newDefaultValue, replaceToken }) => {
|
|
return {
|
|
tagName: 'item',
|
|
content: newDefaultValue,
|
|
attrs: {
|
|
name: replaceToken,
|
|
},
|
|
};
|
|
},
|
|
});
|
|
|
|
const evalExistingEntry: TEvalExistingEntry = (_attrValue, { replaceToken, step }, _qItem) => {
|
|
if (step[0] == 'update')
|
|
return [
|
|
'update',
|
|
{
|
|
attrs: { name: replaceToken },
|
|
},
|
|
];
|
|
};
|
|
|
|
await processQueriedEntries(migrationMap, {
|
|
tagName: 'item',
|
|
containerQuery: 'resources',
|
|
path: `${basePath}../values-night/themes_device_defaults.xml`,
|
|
step: 4,
|
|
evalExistingEntry,
|
|
});
|
|
|
|
await processQueriedEntries(migrationMap, {
|
|
tagName: 'java-symbol',
|
|
path: `${basePath}symbols.xml`,
|
|
containerQuery: 'resources',
|
|
step: 5,
|
|
evalExistingEntry,
|
|
});
|
|
|
|
// update attributes on tracked XML files
|
|
{
|
|
const searchAttrs = [
|
|
'android:color',
|
|
'android:indeterminateTint',
|
|
'app:tint',
|
|
'app:backgroundTint',
|
|
'android:background',
|
|
'android:tint',
|
|
'android:drawableTint',
|
|
'android:textColor',
|
|
'android:fillColor',
|
|
'android:startColor',
|
|
'android:endColor',
|
|
'name',
|
|
'ns1:color',
|
|
];
|
|
|
|
const filtered = new Map(
|
|
[...migrationMap]
|
|
.filter(([_originalToken, { step }]) => step[0] == 'update')
|
|
.map(([originalToken, { replaceToken }]) => [originalToken, replaceToken])
|
|
);
|
|
|
|
const query =
|
|
searchAttrs.map((str) => `*[${str}]`).join(',') +
|
|
[...filtered.keys()].map((originalToken) => `item[name*="${originalToken}"]`).join(',');
|
|
|
|
const trackedFiles = await FileIO.loadFileList(
|
|
`${__dirname}/resources/whitelist/xmls1.json`
|
|
);
|
|
|
|
const promises = trackedFiles.map(async (locaFilePath) => {
|
|
const filePath = `${repoPath}/${locaFilePath}`;
|
|
|
|
const doc = await FileIO.loadXML(filePath);
|
|
const docUpdated = DOM.replaceStringInAttributeValueOnQueried(
|
|
doc.documentElement,
|
|
query,
|
|
searchAttrs,
|
|
filtered
|
|
);
|
|
if (docUpdated) {
|
|
await FileIO.saveFile(DOM.XMLDocToString(doc), filePath);
|
|
} else {
|
|
console.warn(`Failed to update tracked file: '${locaFilePath}'`);
|
|
}
|
|
});
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
// updates tag content on tracked files
|
|
{
|
|
const searchPrefixes = ['?android:attr/', '?androidprv:attr/'];
|
|
const filtered = searchPrefixes
|
|
.reduce<Array<[string, string]>>((acc, prefix) => {
|
|
return [
|
|
...acc,
|
|
...[...migrationMap.entries()]
|
|
.filter(([_originalToken, { step }]) => step[0] == 'update')
|
|
.map(
|
|
([originalToken, { replaceToken }]) =>
|
|
[`${prefix}${originalToken}`, `${prefix}${replaceToken}`] as [
|
|
string,
|
|
string
|
|
]
|
|
),
|
|
];
|
|
}, [])
|
|
.sort((a, b) => b[0].length - a[0].length);
|
|
|
|
const trackedFiles = await FileIO.loadFileList(
|
|
`${__dirname}/resources/whitelist/xmls2.json`
|
|
);
|
|
|
|
const promises = trackedFiles.map(async (locaFilePath) => {
|
|
const filePath = `${repoPath}/${locaFilePath}`;
|
|
const doc = await FileIO.loadXML(filePath);
|
|
const docUpdated = DOM.replaceContentTextOnQueried(
|
|
doc.documentElement,
|
|
'item, color',
|
|
filtered
|
|
);
|
|
if (docUpdated) {
|
|
await FileIO.saveFile(DOM.XMLDocToString(doc), filePath);
|
|
} else {
|
|
console.warn(`Failed to update tracked file: '${locaFilePath}'`);
|
|
}
|
|
});
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
// replace imports on Java / Kotlin
|
|
{
|
|
const replaceMap = new Map(
|
|
[...migrationMap.entries()]
|
|
.filter(([_originalToken, { step }]) => step[0] == 'update')
|
|
.map(
|
|
([originalToken, { replaceToken }]) =>
|
|
[originalToken, replaceToken] as [string, string]
|
|
)
|
|
.sort((a, b) => b[0].length - a[0].length)
|
|
);
|
|
|
|
const trackedFiles = await FileIO.loadFileList(
|
|
`${__dirname}/resources/whitelist/java.json`
|
|
);
|
|
|
|
const promises = trackedFiles.map(async (locaFilePath) => {
|
|
const filePath = `${repoPath}/${locaFilePath}`;
|
|
const fileContent = await FileIO.loadFileAsText(filePath);
|
|
const str = groupReplace(fileContent, replaceMap, 'R.attr.(#group#)(?![a-zA-Z])');
|
|
await FileIO.saveFile(str, filePath);
|
|
});
|
|
await Promise.all(promises);
|
|
}
|
|
}
|
|
|
|
init();
|