Skip to content

Commit

Permalink
📦 Add kdjs usage and declarative worker build
Browse files Browse the repository at this point in the history
  • Loading branch information
KimlikDAO-bot committed Aug 28, 2024
1 parent a483136 commit 78a2de5
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 12 deletions.
63 changes: 63 additions & 0 deletions birimler/builder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env bun
import yaml from "js-yaml";
import { readFile, readdir } from "node:fs/promises";
import { uploadWorker } from "./cloudflare/targets";
import { compileWorker } from "./js/targets";

/** @define {string} */
const ROOT_PATH = "../../..";

/**
* @param {string} dirName
* @return {!Promise<!Object>}
*/
const readBuildRecipe = (dirName) => readdir(dirName)
.then((/** !Array<string> */ dir) => {
for (const file of dir) {
if (!file.startsWith(".") && file.endsWith(".yaml"))
return readFile(`${dirName}/${file}`)
.then((content) => yaml.load(content));
}
return Promise.reject();
});

/**
* @param {string} dirName
* @param {!Object} env
*/
const buildCrate = (dirName, env) => import(`${ROOT_PATH}/${dirName}/build.js`)
.then((buildFile) => buildFile.default && buildFile.default.build
? buildFile.default.build(env)
: Promise.reject())
.catch(() => readBuildRecipe(dirName)
.then((recipe) => {
if (recipe.worker)
compileWorker(dirName, recipe.worker, env);
})
);

/**s
* @param {string} dirName
* @param {!Object} env
*/
const deployCrate = (dirName, env) => import(`${dirName}/build.js`)
.then(
(buildFile) => buildFile.default.deploy(env),
() => readBuildRecipe(dirName)
.then((recipe) => {
if (recipe.worker)
return compileWorker(dirName, recipe.worker)
.then((code) => uploadWorker(env.cloudflare.auth, recipe.worker.name, code))
})
);

/** @dict */
const env = yaml.load(await readFile(".gizli.yaml", "utf8").catch(() => ""));
/** @const {string} */
const crate = process.argv[2] || ".";
/** @const {boolean} */
const isDeploy = process.argv[3] == "deploy";

isDeploy
? deployCrate(crate, env)
: buildCrate(crate, env);
30 changes: 30 additions & 0 deletions birimler/js/targets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { compile } from "../../kdjs/compile";
import { selectDefines, ensureDotJs } from "./util";

/**
* @param {string} dirName
* @param {{
* entry: string,
* defines: !Array<string|({
* module: string,
* value: string
* })>
* }} config
* @param {!Object=} env
* @return {!Promise<string>}
*/
const compileWorker = async (dirName, config, env) => {
/** @const {string} */
const entry = ensureDotJs(`${dirName}/${config.entry}`);
const compileParams = {
entry,
output: `build/${entry}`,
};
if (config.defines)
compileParams.define = selectDefines(entry.slice(0, -3), config.defines, env);
return compile(compileParams);
}

export {
compileWorker
};
46 changes: 43 additions & 3 deletions birimler/js/util.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import yaml from "js-yaml";
import { readFile } from "node:fs/promises";
import toml from "toml";
import { combine } from "../../util/paths";

/**
* @param {string} str
* @return {string}
*/
const ensureDotJs = (str) => str.endsWith(".js") ? str : str + ".js";

/**
* @param {string} str
* @return {string}
*/
const removeDotJs = (str) => str.endsWith(".js") ? str.slice(0, -3) : str;

/**
* @param {string} definesFile
Expand All @@ -10,12 +23,33 @@ const readDefines = (definesFile, module) => readFile(definesFile)
.then(
(fileContent) => {
const moduleName = module.replaceAll("/", "$");
return Object.entries(toml.parse(fileContent)).map(
return Object.entries(yaml.load(fileContent)).map(
([key, value]) => `${key}$$module$${moduleName}="${value}"`)
},
() => []
)

const selectDefines = (module, defines, env) => {
const out = [];
for (const define of defines) {
const [mod, key] = typeof define == "string"
? [module, define]
: [removeDotJs(define.module.startsWith("/")
? define.module.slice(1)
: combine(module, "../" + define.module)), define.value];

let val = env;
if (env)
for (const k of key.split("."))
val = val[k];

/** @const {string} */
const varName = key.replaceAll(".", "_").toUpperCase();
out.push(`${varName}$$module$${mod.replaceAll("/", "$")}=${JSON.stringify(val)}`);
}
return out;
}

/**
* @param {string} module
* @param {string} name
Expand All @@ -25,4 +59,10 @@ const readDefines = (definesFile, module) => readFile(definesFile)
const define = (module, name, value) =>
`${name}$$module$${module.replaceAll("/", "$")}=${value}`;

export { define, readDefines };
export {
define,
ensureDotJs,
readDefines,
removeDotJs,
selectDefines
};
2 changes: 2 additions & 0 deletions crypto/sha3.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ const keccak256Uint32ToHex = (words) => hex.from(
new Uint8Array(keccak256Uint32(words).buffer, 0, 32));

/**
* @pureOrBreakMyCode
* @nosideeffects
* @param {string} str A string to be hashed.
* @return {string} hex encoded hash.
*/
Expand Down
50 changes: 46 additions & 4 deletions kdjs/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,52 @@
# KimlikDAO js compiler
# `kdjs`: KimlikDAO JavaScript compiler

Primarily wraps Google Closure Compiler (GCC) and UglifyJS but adds additional functionality
to GCC such as ability to compile es6 modules.
`kdjs` is a javascript compiler with advanced optimization and minification capabilities.
It primarily builds upon the Google Closure Compiler (GCC) however it has many custom optimization
passes and a more powerful module system.

For instance, `kdjs` it is able to generate es6 modules with `export`s and unlinked `import`s, which
is not possible with GCC.

`kdjs` expects your code to be fully annotated using the Google Closure Compiler type annotations.
Just like in GCC, your type annotations can be either in a `.js` file or an externs file, which in `kdjs`
has to end with the extension `.d.js`.

You can run `kdjs` directly

```shell
bun kdjs/kdjs.js entry.js
```

`kdjs` will automatically crawl all the imported files from the entry.js and include the externs files for libraries that it recognizes.
or install it system wide

```shell
cd kdjs
npm i -g .
```

When you run `kdjs` with a supplied entry file like so

```shell
$ kdjs entry.js
```

it will automatically crawl all the imported files from the entry.js and
include the externs files for libraries that it recognizes.

```shell
$ kdjs

kdjs 0.0.1

Usage: kdjs entry.js [parameters]

Parameters:
--output (-o) : The name of the output file
--print : Print the compiled code to stdout
--strict : Report unknown type
--loose : Don't perform strictTypeCheck
--nologs : Strip all console.log() calls
--define : Values for @define annotated variables
--isolateDir : Directory name to write the isolated and preprocessed input files
--emit_shebang : Whether to place bun shebang sequence at the beginning of the output
```
4 changes: 3 additions & 1 deletion kdjs/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const compile = async (params, checkFreshFn) => {
},
toplevel: true,
compress: {
// evaluate: "eager",
module: true,
toplevel: true,
passes: 3,
Expand All @@ -97,8 +98,9 @@ const compile = async (params, checkFreshFn) => {
console.log(`Uglified size:\t${uglified.code.length}\nGCC size:\t${output.length}`);
let code = uglified.code.length < output.length ? uglified.code : output;
if (/** @type {boolean} */(params["emit_shebang"]))
code = "#!/usr/bin/env node\n" + code;
code = "#!/usr/bin/env bun\n" + code;
console.log(uglified.warnings, uglified.error);
if (params["print"]) console.log(code);
if (params["output"])
writeFile(/** @type {string} */(params["output"]), code)
.then(() => resolve(code))
Expand Down
20 changes: 19 additions & 1 deletion kdjs/kdjs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env node

import { writeFile } from "node:fs/promises";
import process from "node:process";
import { parseArgs } from "../util/cli";
import { compile } from "./compile";
Expand All @@ -9,6 +8,25 @@ const params = parseArgs(process.argv.slice(2), "entry", {
"-o": "output",
"-d": "exports",
});

if (typeof params["entry"] != "string") {
console.log(`kdjs 0.0.1
Usage: kdjs entry.js [parameters]
Parameters:
--output (-o) : The name of the output file
--print : Print the compiled code to stdout
--strict : Report unknown type
--loose : Don't perform strictTypeCheck
--nologs : Strip all console.log() calls
--define : Values for @define annotated variables
--isolateDir : Directory name to write the isolated and preprocessed input files
--emit_shebang : Whether to place bun shebang sequence at the beginning of the output
`);
process.exit(0);
}

params["output"] ||= /** @type {string} */(params["entry"])
.replace(/\.js$/, ".out.js");

Expand Down
6 changes: 3 additions & 3 deletions kdjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
"optimize"
],
"dependencies": {
"acorn": "^8.12.0",
"acorn": "^8.12.1",
"acorn-walk": "^8.3.3",
"astring": "^1.8.6",
"astring": "^1.9.0",
"google-closure-compiler": "^20240317.0.0",
"uglify-js": "^3.18.0"
"uglify-js": "^3.19.2"
}
}

0 comments on commit 78a2de5

Please sign in to comment.