UNPKG

xcparse

Version:

pbxproj parser

212 lines 7.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Writer = void 0; const referenceBuilder_1 = require("./referenceBuilder"); const unicode_1 = require("./unicode"); let EOL = "\n"; try { EOL = require("os").EOL; } catch { } function isObject(value) { return (typeof value === "object" && value !== null && !(value instanceof Buffer)); } /** Ensure string values that use invalid characters are wrapped in quotes. */ function ensureQuotes(value) { value = (0, unicode_1.addQuotes)(value); // Seems like no hyphen is the wehhh if (/^[\w_$/:.]+$/.test(value)) { // if (/^[\w_$/:.-]+$/.test(value)) { return value; } return `"${value}"`; } // TODO: How to handle buffer? <xx xx xx> function formatData(data) { return `<${data.toString()}>`; } function getSortedObjects(objects) { const sorted = {}; // sort by isa Object.entries(objects).forEach(([id, object]) => { if (!sorted[object.isa]) { sorted[object.isa] = []; } sorted[object.isa].push([id, object]); }); // alphabetize by isa like Xcode return Object.entries(sorted).sort(); } class Writer { constructor(project, options = {}) { this.project = project; this.options = options; this.indent = 0; this.contents = ""; this.comments = {}; this.comments = (0, referenceBuilder_1.createReferenceList)(project); this.writeShebang(); this.writeProject(); } pad(x) { // \t might also work... const tab = this.options.tab ?? "\t"; return x > 0 ? tab + this.pad(x - 1) : ""; // return x > 0 ? " " + pad(x - 1) : ""; } getResults() { return this.contents; } println(string) { this.contents += this.pad(this.indent); this.contents += string; this.contents += EOL; } write(string) { this.contents += this.pad(this.indent); this.contents += string; } printAssignLn(key, value) { return this.println(key + " = " + value + ";"); } flush(string) { const current = this.indent; this.indent = 0; this.write(string); this.indent = current; } writeShebang() { const headComment = this.options?.shebang ?? "!$*UTF8*$!"; this.println(`// ${headComment}`); } /** Format ID with optional comment reference. */ formatId(id, cmt = this.comments[id]) { if (cmt) { // 13B07F961A680F5B00A75B9A /* yolo87.app */ return `${id} /* ${cmt} */`; } // If there is no reference then we might need to wrap with quotes. return ensureQuotes(id); } writeProject() { this.println("{"); if (this.project) { this.indent++; this.writeObject(this.project, true); this.indent--; } this.println("}"); } writeObject(object, isBase) { Object.entries(object).forEach(([key, value]) => { if (this.options.skipNullishValues && value == null) { return; } else if (value instanceof Buffer) { this.printAssignLn(ensureQuotes(key), formatData(value)); } else if (Array.isArray(value)) { this.writeArray(key, value); } else if (isObject(value)) { // Deeper empty objects should be inlined. if (!isBase && !Object.keys(value).length) { this.println(ensureQuotes(key) + " = {};"); return; } this.println(ensureQuotes(key) + " = {"); this.indent++; if (isBase && key === "objects") { this.writePbxObjects(value); } else { this.writeObject(value, isBase); } this.indent--; this.println("};"); } else { this.printAssignLn(ensureQuotes(key), key === "remoteGlobalIDString" ? ensureQuotes(value) : this.formatId(value)); } }); } writePbxObjects(projectObjects) { getSortedObjects(projectObjects).forEach(([isa, objects]) => { this.flush(EOL); this.flush(`/* Begin ${isa} section */` + EOL); objects.forEach(([id, obj]) => this.writeObjectInclusive(id, obj)); this.flush(`/* End ${isa} section */` + EOL); }); } writeArray(key, value) { this.println(ensureQuotes(key) + " = ("); this.indent++; value.forEach((item) => { // TODO: Nested arrays? if (item instanceof Buffer) { this.println(formatData(item) + ","); } else if (item == null) { return; } else if (isObject(item)) { this.println("{"); if (item) { this.indent++; this.writeObject(item); this.indent--; } this.println("},"); } else { this.println(this.formatId(String(item)) + ","); } }); this.indent--; this.println(");"); } writeObjectInclusive(key, value) { if ((0, referenceBuilder_1.isPBXBuildFile)(value) || (0, referenceBuilder_1.isPBXFileReference)(value)) { return this.writeObjectWithoutIndent(key, value); } this.println(this.formatId(key) + " = {"); /* foo = { */ this.indent++; /* */ this.writeObject(value); this.indent--; /* }; */ this.println("};"); } writeObjectWithoutIndent(key, value) { const line = []; const buildInline = (key, value) => { line.push(this.formatId(key) + " = {"); Object.entries(value).forEach(([key, obj]) => { if (this.options.skipNullishValues && obj == null) { return; } else if (obj instanceof Buffer) { line.push(ensureQuotes(key) + " = " + formatData(obj) + "; "); } else if (Array.isArray(obj)) { line.push(ensureQuotes(key) + " = ("); obj.forEach((item) => line.push(ensureQuotes(item) + ", ")); line.push("); "); } else if (isObject(obj)) { buildInline(key, obj); } else { line.push(ensureQuotes(key) + " = " + this.formatId(obj) + "; "); } }); line.push("}; "); }; buildInline(key, value); this.println(line.join("").trim()); } } exports.Writer = Writer; //# sourceMappingURL=writer.js.map