Skip to content

Commit

Permalink
chore: update compression algorithm for objects
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhe committed Mar 27, 2024
1 parent 2e64070 commit 37e7b88
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,26 @@ module.exports = class CompressionAlgorithm {
*/
verifyImplementation() {
const tempFile = path.join(__dirname, "..", "temp", `__${uuid.v4()}tmp.js`); // defeat require-cache.
let original = 0;
let compressed = 1;
const original = this.data;
let compressed = { x: "compressed code string read failure" };
try {
fs.writeFileSync(tempFile, this.toCodeString("module.exports = $"), "utf-8");
original = this.toJsonString(this.data);
compressed = this.toJsonString(require(tempFile));
} catch (e) {}
compressed = require(tempFile);
} catch (e) {
console.error(e);
}
fs.rmSync(tempFile);
if (original !== compressed) {
fs.writeFileSync(path.join(__dirname, "..", "temp", "__original.json"), original);
fs.writeFileSync(path.join(__dirname, "..", "temp", "__compressed.json"), compressed);
try {
assert.deepStrictEqual(
original,
compressed,
`Compression implementation is not correct for ${this.constructor.name}.`
);
} catch (e) {
fs.writeFileSync(path.join(__dirname, "..", "temp", "__original.json"), JSON.stringify(original, null, 2));
fs.writeFileSync(path.join(__dirname, "..", "temp", "__compressed.json"), JSON.stringify(original, null, 2));
throw e;
}
assert(original === compressed, `Compression implementation is not correct for ${this.constructor.name}.`);
}

/**
Expand All @@ -55,6 +62,9 @@ module.exports = class CompressionAlgorithm {
case "undefined":
break;
case "object":
if (null === data) {
break;
}
if (Array.isArray(data)) {
buffer += `\n` + indent + `[\n`;
for (let i = 0; i < data.length; ++i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ module.exports = class PatternDetection extends CompressionAlgorithm {
if (carry) {
this.varName.push(0);
}

if (["in", "do", "if", "else", "try", "catch", "return"].includes(out)) {
return this.nextVariableName();
}

return out;
}

Expand Down Expand Up @@ -238,6 +243,7 @@ module.exports = class PatternDetection extends CompressionAlgorithm {
}
}

return aStartChar < bStartChar ? -1 : 1;
throw new Error(`unexpected start char: ${aStartChar}, ${bStartChar}`);
});

Expand Down Expand Up @@ -285,7 +291,8 @@ module.exports = class PatternDetection extends CompressionAlgorithm {
if (found.length > 1 && key.length * found.length > 8) {
const symbol = this.nextVariableName();
keyVarBuffer.push(`${symbol}="${key}"`);
buffer = buffer.replaceAll(new RegExp(`"?${key}"?:([^ ])`, "g"), `[${symbol}]:$1`);
buffer = buffer.replaceAll(new RegExp(`"${key}":([^ ])`, "g"), `[${symbol}]:$1`);
buffer = buffer.replaceAll(new RegExp(`([,{\n])${key}:([^ ])`, "g"), `$1[${symbol}]:$2`);
}
}
if (keyVarBuffer.length > 0) {
Expand Down
65 changes: 65 additions & 0 deletions scripts/smithy-model/compress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const fs = require("fs");
const path = require("path");

const RemoveWhitespace = require("../endpoints-ruleset/compression-algorithms/RemoveWhitespace");
const PatternDetection = require("../endpoints-ruleset/compression-algorithms/PatternDetection");
const { getPrunedModelObject } = require("./getPrunedModelObject");

/**
* Run compression on model objects for SDK clients.
*/
const main = (singleModel = "lambda") => {
const root = path.join(__dirname, "..", "..");
const modelsFolder = path.join(root, "codegen", "sdk-codegen", "aws-models");
const modelsList = singleModel ? [`${singleModel}.json`] : fs.readdirSync(modelsFolder);

/**
* The first algorithm which passes self-verification will be used.
*/
const compressionAlgorithms = [(data) => new PatternDetection(data), (data) => new RemoveWhitespace(data)];

for (const modelJsonFilename of modelsList) {
const client = modelJsonFilename.replace(".json", "");
const serviceJson = path.join(modelsFolder, modelJsonFilename);

const service = require(serviceJson);

const data = getPrunedModelObject(service);

let selectedAlgorithm = null;
for (const factory of compressionAlgorithms) {
const algo = factory(data);
try {
algo.verifyImplementation();
selectedAlgorithm = factory(data);
break;
} catch (e) {
const sample = factory(data).toCodeString("module.exports = $;");
fs.writeFileSync(
path.join(path.join(__dirname, "temp", client + `-failed-${factory(data).constructor.name}.js`)),
sample,
"utf-8"
);
console.warn(`WARN: Algorithm ${algo.constructor.name} failed for ${client}.`);
}
}

if (!selectedAlgorithm) {
throw new Error(`No viable algorithm for ${client}`);
}

const modifiedSource = `// @ts-nocheck
// generated code, do not edit
/* This file is a compressed version of ./codegen/sdk-codegen/aws-models/${client}.json */
${selectedAlgorithm.toCodeString("module.exports = $;")}
`;

fs.writeFileSync(path.join(__dirname, "temp", `${client}.min.js`), modifiedSource, "utf-8");
console.log(client, `OK - ${selectedAlgorithm.constructor.name}`);
}

return 0;
};

main();
35 changes: 35 additions & 0 deletions scripts/smithy-model/getPrunedModelObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const removeKeys = [
"metadata",
"smithy.api#length",
"smithy.api#range",
"smithy.api#pattern",
"smithy.rules#endpointRuleSet",
"smithy.rules#endpointTests",
];

/**
* Remove entries from model not required for runtime:
*/
const getPrunedModelObject = (data) => {
const prunedData = data;
if (!data || typeof data !== "object") {
return prunedData;
}
for (const key in prunedData) {
if (key === "documentation" || key === "smithy.api#documentation") {
delete prunedData[key];
continue;
}
if (removeKeys.includes(key)) {
delete prunedData[key];
continue;
}
prunedData[key] = getPrunedModelObject(prunedData[key]);
}
if (prunedData.traits && Object.keys(prunedData.traits).length === 0) {
delete prunedData.traits;
}
return prunedData;
};

module.exports = { getPrunedModelObject };

0 comments on commit 37e7b88

Please sign in to comment.