Loading packages/SystemUI/scripts/token_alignment/.eslintrc.json 0 → 100644 +31 −0 Original line number Diff line number Diff line { "env": { "es2021": true, "node": true }, "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, "plugins": ["prettier", "@typescript-eslint", "eslint-plugin-simple-import-sort", "import"], "extends": ["prettier", "eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { "prettier/prettier": ["error"], "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ "warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" } ], "no-multiple-empty-lines": ["error", { "max": 2 }], "no-multi-spaces": "error", "simple-import-sort/imports": "error", "simple-import-sort/exports": "error", "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error" } } packages/SystemUI/scripts/token_alignment/.gitignore 0 → 100644 +2 −0 Original line number Diff line number Diff line vscode node_modules No newline at end of file packages/SystemUI/scripts/token_alignment/.prettierrc 0 → 100644 +9 −0 Original line number Diff line number Diff line { "tabWidth": 4, "printWidth": 100, "semi": true, "singleQuote": true, "bracketSameLine": true, "bracketSpacing": true, "arrowParens": "always" } No newline at end of file packages/SystemUI/scripts/token_alignment/helpers/DOMFuncs.ts 0 → 100644 +297 −0 Original line number Diff line number Diff line // 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. type IElementComment = | { commentNode: undefined; textContent: undefined; hidden: undefined } | { commentNode: Node; textContent: string; hidden: boolean }; interface ITag { attrs?: Record<string, string | number>; tagName: string; } export interface INewTag extends ITag { content?: string | number; comment?: string; } export type IUpdateTag = Partial<Omit<INewTag, 'tagName'>>; export default class DOM { static addEntry(containerElement: Element, tagOptions: INewTag) { const doc = containerElement.ownerDocument; const exists = this.alreadyHasEntry(containerElement, tagOptions); if (exists) { console.log('Ignored adding entry already available: ', exists.outerHTML); return; } let insertPoint: Node | null = containerElement.lastElementChild; //.childNodes[containerElement.childNodes.length - 1]; if (!insertPoint) { console.log('Ignored adding entry in empity parent: ', containerElement.outerHTML); return; } const { attrs, comment, content, tagName } = tagOptions; if (comment) { const commentNode = doc.createComment(comment); this.insertAfterIdented(commentNode, insertPoint); insertPoint = commentNode; } const newEl = doc.createElement(tagName); if (content) newEl.innerHTML = content.toString(); if (attrs) Object.entries(attrs).forEach(([attr, value]) => newEl.setAttribute(attr, value.toString()) ); this.insertAfterIdented(newEl, insertPoint); return true; } static insertBeforeIndented(newNode: Node, referenceNode: Node) { const paddingNode = referenceNode.previousSibling; const ownerDoc = referenceNode.ownerDocument; const containerNode = referenceNode.parentNode; if (!paddingNode || !ownerDoc || !containerNode) return; const currentPadding = paddingNode.textContent || ''; const textNode = referenceNode.ownerDocument.createTextNode(currentPadding); containerNode.insertBefore(newNode, referenceNode); containerNode.insertBefore(textNode, newNode); } static insertAfterIdented(newNode: Node, referenceNode: Node) { const paddingNode = referenceNode.previousSibling; const ownerDoc = referenceNode.ownerDocument; const containerNode = referenceNode.parentNode; if (!paddingNode || !ownerDoc || !containerNode) return; const currentPadding = paddingNode.textContent || ''; const textNode = ownerDoc.createTextNode(currentPadding); containerNode.insertBefore(newNode, referenceNode.nextSibling); containerNode.insertBefore(textNode, newNode); } static getElementComment(el: Element): IElementComment { const commentNode = el.previousSibling?.previousSibling; const out = { commentNode: undefined, textContent: undefined, hidden: undefined }; if (!commentNode) return out; const textContent = commentNode.textContent || ''; const hidden = textContent.substring(textContent.length - 6) == '@hide '; if (!(commentNode && commentNode.nodeName == '#comment')) return out; return { commentNode, textContent, hidden: hidden }; } static duplicateEntryWithChange( templateElement: Element, options: Omit<IUpdateTag, 'content'> ) { const exists = this.futureEntryAlreadyExist(templateElement, options); if (exists) { console.log('Ignored duplicating entry already available: ', exists.outerHTML); return; } const { commentNode } = this.getElementComment(templateElement); let insertPoint: Node = templateElement; if (commentNode) { const newComment = commentNode.cloneNode(); this.insertAfterIdented(newComment, insertPoint); insertPoint = newComment; } const newEl = templateElement.cloneNode(true) as Element; this.insertAfterIdented(newEl, insertPoint); this.updateElement(newEl, options); return true; } static replaceStringInAttributeValueOnQueried( root: Element, query: string, attrArray: string[], replaceMap: Map<string, string> ): boolean { let updated = false; const queried = [...Array.from(root.querySelectorAll(query)), root]; queried.forEach((el) => { attrArray.forEach((attr) => { if (el.hasAttribute(attr)) { const currentAttrValue = el.getAttribute(attr); if (!currentAttrValue) return; [...replaceMap.entries()].some(([oldStr, newStr]) => { if ( currentAttrValue.length >= oldStr.length && currentAttrValue.indexOf(oldStr) == currentAttrValue.length - oldStr.length ) { el.setAttribute(attr, currentAttrValue.replace(oldStr, newStr)); updated = true; return true; } return false; }); } }); }); return updated; } static updateElement(el: Element, updateOptions: IUpdateTag) { const exists = this.futureEntryAlreadyExist(el, updateOptions); if (exists) { console.log('Ignored updating entry already available: ', exists.outerHTML); return; } const { comment, attrs, content } = updateOptions; if (comment) { const { commentNode } = this.getElementComment(el); if (commentNode) { commentNode.textContent = comment; } } if (attrs) { for (const attr in attrs) { const value = attrs[attr]; if (value != undefined) { el.setAttribute(attr, `${value}`); } else { el.removeAttribute(attr); } } } if (content != undefined) { el.innerHTML = `${content}`; } return true; } static elementToOptions(el: Element): ITag { return { attrs: this.getAllElementAttributes(el), tagName: el.tagName, }; } static getAllElementAttributes(el: Element): Record<string, string> { return el .getAttributeNames() .reduce( (acc, attr) => ({ ...acc, [attr]: el.getAttribute(attr) || '' }), {} as Record<string, string> ); } static futureEntryAlreadyExist(el: Element, updateOptions: IUpdateTag) { const currentElOptions = this.elementToOptions(el); if (!el.parentElement) { console.log('Checked el has no parent'); process.exit(); } return this.alreadyHasEntry(el.parentElement, { ...currentElOptions, ...updateOptions, attrs: { ...currentElOptions.attrs, ...updateOptions.attrs }, }); } static alreadyHasEntry( containerElement: Element, { attrs, tagName }: Pick<INewTag, 'attrs' | 'tagName'> ) { const qAttrs = attrs ? Object.entries(attrs) .map(([a, v]) => `[${a}="${v}"]`) .join('') : ''; return containerElement.querySelector(tagName + qAttrs); } static replaceContentTextOnQueried( root: Element, query: string, replacePairs: Array<[string, string]> ) { let updated = false; let queried = Array.from(root.querySelectorAll(query)); if (queried.length == 0) queried = [...Array.from(root.querySelectorAll(query)), root]; queried.forEach((el) => { replacePairs.forEach(([oldStr, newStr]) => { if (el.innerHTML == oldStr) { el.innerHTML = newStr; updated = true; } }); }); return updated; } static XMLDocToString(doc: XMLDocument) { let str = ''; doc.childNodes.forEach((node) => { switch (node.nodeType) { case 8: // comment str += `<!--${node.nodeValue}-->\n`; break; case 3: // text str += node.textContent; break; case 1: // element str += (node as Element).outerHTML; break; default: console.log('Unhandled node type: ' + node.nodeType); break; } }); return str; } } packages/SystemUI/scripts/token_alignment/helpers/FileIO.ts 0 → 100644 +112 −0 Original line number Diff line number Diff line // 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 { exec } from 'child_process'; import { parse } from 'csv-parse'; import { promises as fs } from 'fs'; import jsdom from 'jsdom'; const DOMParser = new jsdom.JSDOM('').window.DOMParser as typeof window.DOMParser; type TFileList = string[]; export type TCSVRecord = Array<string | boolean | number>; class _FileIO { public parser = new DOMParser(); public saved: string[] = []; public loadXML = async (path: string): Promise<XMLDocument> => { try { const src = await this.loadFileAsText(path); return this.parser.parseFromString(src, 'text/xml') as XMLDocument; } catch (error) { console.log(`Failed to parse XML file '${path}'.`, error); process.exit(); } }; public loadFileAsText = async (path: string): Promise<string> => { try { return await fs.readFile(path, { encoding: 'utf8' }); } catch (error) { console.log(`Failed to read file '${path}'.`, error); process.exit(); } }; public saveFile = async (data: string, path: string) => { try { await fs.writeFile(path, data, { encoding: 'utf8' }); this.saved.push(path); } catch (error) { console.log(error); console.log(`Failed to write file '${path}'.`); process.exit(); } }; public loadFileList = async (path: string): Promise<TFileList> => { const src = await this.loadFileAsText(path); try { return JSON.parse(src) as TFileList; } catch (error) { console.log(error); console.log(`Failed to parse JSON file '${path}'.`); process.exit(); } }; public loadCSV = (path: string): Promise<Array<TCSVRecord>> => { return new Promise((resolve, reject) => { this.loadFileAsText(path).then((src) => { parse( src, { delimiter: ' ', }, (err, records) => { if (err) { reject(err); return; } resolve(records); } ); }); }); }; formatSaved = () => { const cmd = `idea format ${this.saved.join(' ')}`; exec(cmd, (error, out, stderr) => { if (error) { console.log(error.message); return; } if (stderr) { console.log(stderr); return; } console.log(out); }); }; } export const FileIO = new _FileIO(); Loading
packages/SystemUI/scripts/token_alignment/.eslintrc.json 0 → 100644 +31 −0 Original line number Diff line number Diff line { "env": { "es2021": true, "node": true }, "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" }, "plugins": ["prettier", "@typescript-eslint", "eslint-plugin-simple-import-sort", "import"], "extends": ["prettier", "eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { "prettier/prettier": ["error"], "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ "warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" } ], "no-multiple-empty-lines": ["error", { "max": 2 }], "no-multi-spaces": "error", "simple-import-sort/imports": "error", "simple-import-sort/exports": "error", "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error" } }
packages/SystemUI/scripts/token_alignment/.gitignore 0 → 100644 +2 −0 Original line number Diff line number Diff line vscode node_modules No newline at end of file
packages/SystemUI/scripts/token_alignment/.prettierrc 0 → 100644 +9 −0 Original line number Diff line number Diff line { "tabWidth": 4, "printWidth": 100, "semi": true, "singleQuote": true, "bracketSameLine": true, "bracketSpacing": true, "arrowParens": "always" } No newline at end of file
packages/SystemUI/scripts/token_alignment/helpers/DOMFuncs.ts 0 → 100644 +297 −0 Original line number Diff line number Diff line // 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. type IElementComment = | { commentNode: undefined; textContent: undefined; hidden: undefined } | { commentNode: Node; textContent: string; hidden: boolean }; interface ITag { attrs?: Record<string, string | number>; tagName: string; } export interface INewTag extends ITag { content?: string | number; comment?: string; } export type IUpdateTag = Partial<Omit<INewTag, 'tagName'>>; export default class DOM { static addEntry(containerElement: Element, tagOptions: INewTag) { const doc = containerElement.ownerDocument; const exists = this.alreadyHasEntry(containerElement, tagOptions); if (exists) { console.log('Ignored adding entry already available: ', exists.outerHTML); return; } let insertPoint: Node | null = containerElement.lastElementChild; //.childNodes[containerElement.childNodes.length - 1]; if (!insertPoint) { console.log('Ignored adding entry in empity parent: ', containerElement.outerHTML); return; } const { attrs, comment, content, tagName } = tagOptions; if (comment) { const commentNode = doc.createComment(comment); this.insertAfterIdented(commentNode, insertPoint); insertPoint = commentNode; } const newEl = doc.createElement(tagName); if (content) newEl.innerHTML = content.toString(); if (attrs) Object.entries(attrs).forEach(([attr, value]) => newEl.setAttribute(attr, value.toString()) ); this.insertAfterIdented(newEl, insertPoint); return true; } static insertBeforeIndented(newNode: Node, referenceNode: Node) { const paddingNode = referenceNode.previousSibling; const ownerDoc = referenceNode.ownerDocument; const containerNode = referenceNode.parentNode; if (!paddingNode || !ownerDoc || !containerNode) return; const currentPadding = paddingNode.textContent || ''; const textNode = referenceNode.ownerDocument.createTextNode(currentPadding); containerNode.insertBefore(newNode, referenceNode); containerNode.insertBefore(textNode, newNode); } static insertAfterIdented(newNode: Node, referenceNode: Node) { const paddingNode = referenceNode.previousSibling; const ownerDoc = referenceNode.ownerDocument; const containerNode = referenceNode.parentNode; if (!paddingNode || !ownerDoc || !containerNode) return; const currentPadding = paddingNode.textContent || ''; const textNode = ownerDoc.createTextNode(currentPadding); containerNode.insertBefore(newNode, referenceNode.nextSibling); containerNode.insertBefore(textNode, newNode); } static getElementComment(el: Element): IElementComment { const commentNode = el.previousSibling?.previousSibling; const out = { commentNode: undefined, textContent: undefined, hidden: undefined }; if (!commentNode) return out; const textContent = commentNode.textContent || ''; const hidden = textContent.substring(textContent.length - 6) == '@hide '; if (!(commentNode && commentNode.nodeName == '#comment')) return out; return { commentNode, textContent, hidden: hidden }; } static duplicateEntryWithChange( templateElement: Element, options: Omit<IUpdateTag, 'content'> ) { const exists = this.futureEntryAlreadyExist(templateElement, options); if (exists) { console.log('Ignored duplicating entry already available: ', exists.outerHTML); return; } const { commentNode } = this.getElementComment(templateElement); let insertPoint: Node = templateElement; if (commentNode) { const newComment = commentNode.cloneNode(); this.insertAfterIdented(newComment, insertPoint); insertPoint = newComment; } const newEl = templateElement.cloneNode(true) as Element; this.insertAfterIdented(newEl, insertPoint); this.updateElement(newEl, options); return true; } static replaceStringInAttributeValueOnQueried( root: Element, query: string, attrArray: string[], replaceMap: Map<string, string> ): boolean { let updated = false; const queried = [...Array.from(root.querySelectorAll(query)), root]; queried.forEach((el) => { attrArray.forEach((attr) => { if (el.hasAttribute(attr)) { const currentAttrValue = el.getAttribute(attr); if (!currentAttrValue) return; [...replaceMap.entries()].some(([oldStr, newStr]) => { if ( currentAttrValue.length >= oldStr.length && currentAttrValue.indexOf(oldStr) == currentAttrValue.length - oldStr.length ) { el.setAttribute(attr, currentAttrValue.replace(oldStr, newStr)); updated = true; return true; } return false; }); } }); }); return updated; } static updateElement(el: Element, updateOptions: IUpdateTag) { const exists = this.futureEntryAlreadyExist(el, updateOptions); if (exists) { console.log('Ignored updating entry already available: ', exists.outerHTML); return; } const { comment, attrs, content } = updateOptions; if (comment) { const { commentNode } = this.getElementComment(el); if (commentNode) { commentNode.textContent = comment; } } if (attrs) { for (const attr in attrs) { const value = attrs[attr]; if (value != undefined) { el.setAttribute(attr, `${value}`); } else { el.removeAttribute(attr); } } } if (content != undefined) { el.innerHTML = `${content}`; } return true; } static elementToOptions(el: Element): ITag { return { attrs: this.getAllElementAttributes(el), tagName: el.tagName, }; } static getAllElementAttributes(el: Element): Record<string, string> { return el .getAttributeNames() .reduce( (acc, attr) => ({ ...acc, [attr]: el.getAttribute(attr) || '' }), {} as Record<string, string> ); } static futureEntryAlreadyExist(el: Element, updateOptions: IUpdateTag) { const currentElOptions = this.elementToOptions(el); if (!el.parentElement) { console.log('Checked el has no parent'); process.exit(); } return this.alreadyHasEntry(el.parentElement, { ...currentElOptions, ...updateOptions, attrs: { ...currentElOptions.attrs, ...updateOptions.attrs }, }); } static alreadyHasEntry( containerElement: Element, { attrs, tagName }: Pick<INewTag, 'attrs' | 'tagName'> ) { const qAttrs = attrs ? Object.entries(attrs) .map(([a, v]) => `[${a}="${v}"]`) .join('') : ''; return containerElement.querySelector(tagName + qAttrs); } static replaceContentTextOnQueried( root: Element, query: string, replacePairs: Array<[string, string]> ) { let updated = false; let queried = Array.from(root.querySelectorAll(query)); if (queried.length == 0) queried = [...Array.from(root.querySelectorAll(query)), root]; queried.forEach((el) => { replacePairs.forEach(([oldStr, newStr]) => { if (el.innerHTML == oldStr) { el.innerHTML = newStr; updated = true; } }); }); return updated; } static XMLDocToString(doc: XMLDocument) { let str = ''; doc.childNodes.forEach((node) => { switch (node.nodeType) { case 8: // comment str += `<!--${node.nodeValue}-->\n`; break; case 3: // text str += node.textContent; break; case 1: // element str += (node as Element).outerHTML; break; default: console.log('Unhandled node type: ' + node.nodeType); break; } }); return str; } }
packages/SystemUI/scripts/token_alignment/helpers/FileIO.ts 0 → 100644 +112 −0 Original line number Diff line number Diff line // 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 { exec } from 'child_process'; import { parse } from 'csv-parse'; import { promises as fs } from 'fs'; import jsdom from 'jsdom'; const DOMParser = new jsdom.JSDOM('').window.DOMParser as typeof window.DOMParser; type TFileList = string[]; export type TCSVRecord = Array<string | boolean | number>; class _FileIO { public parser = new DOMParser(); public saved: string[] = []; public loadXML = async (path: string): Promise<XMLDocument> => { try { const src = await this.loadFileAsText(path); return this.parser.parseFromString(src, 'text/xml') as XMLDocument; } catch (error) { console.log(`Failed to parse XML file '${path}'.`, error); process.exit(); } }; public loadFileAsText = async (path: string): Promise<string> => { try { return await fs.readFile(path, { encoding: 'utf8' }); } catch (error) { console.log(`Failed to read file '${path}'.`, error); process.exit(); } }; public saveFile = async (data: string, path: string) => { try { await fs.writeFile(path, data, { encoding: 'utf8' }); this.saved.push(path); } catch (error) { console.log(error); console.log(`Failed to write file '${path}'.`); process.exit(); } }; public loadFileList = async (path: string): Promise<TFileList> => { const src = await this.loadFileAsText(path); try { return JSON.parse(src) as TFileList; } catch (error) { console.log(error); console.log(`Failed to parse JSON file '${path}'.`); process.exit(); } }; public loadCSV = (path: string): Promise<Array<TCSVRecord>> => { return new Promise((resolve, reject) => { this.loadFileAsText(path).then((src) => { parse( src, { delimiter: ' ', }, (err, records) => { if (err) { reject(err); return; } resolve(records); } ); }); }); }; formatSaved = () => { const cmd = `idea format ${this.saved.join(' ')}`; exec(cmd, (error, out, stderr) => { if (error) { console.log(error.message); return; } if (stderr) { console.log(stderr); return; } console.log(out); }); }; } export const FileIO = new _FileIO();