initial commit

master
Drake 3 months ago
commit 1ed54ce481
  1. 1
      .gitignore
  2. 13
      LICENSE
  3. 40
      README.md
  4. BIN
      assets/comparison.png
  5. 20
      package.json
  6. 85
      pnpm-lock.yaml
  7. 96
      src/main.js
  8. 6
      test/out.js
  9. 21
      test/rollup.config.mjs
  10. 18
      test/test.js

1
.gitignore vendored

@ -0,0 +1 @@
node_modules

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

@ -0,0 +1,40 @@
# rollup-plugin-preprocessor
A Rollup plugin that adds a C-like preprocessor to Javascript.
# Screenshots
![Very useful comparison image (this is a lie)](assets/comparison.png)
# Documentation
## Options
This plugin exports a `preprocess()` plugin function that takes in an options object with the following syntax:
```js
{
//a list of compile-time variables and their values (parsed to an AST, so all JS is valid)
//NOTE: due to this, strings require single quotes around them to parse to String
values: {
EXAMPLE: "'Hello, world!'",
IS_TRUE: 1,
WEBPACK: "demon.summon('modules/webpack')"
},
//a list of comment transformations
transforms: {
//example: this deletes all comments that start with NONPROD in the output AST
NONPROD: (node, parent, idx) => {parent.comments = []}
}
}
```
## Included Directives
This plugin currently includes 3, battle-tested, production-ready directives for any code you may want to use them in.
`#IF comptime_var` - If `comptime_var` evaluates to true, the code from it until the end is included in the output; otherwise, it is ignored.
`#IFNOT comptime_var` - If `comptime_var` evaluates to false, the code from it until the end is included in the output; otherwise, it is ignored.
`#END` - Ends an `#IF`/`#IFNOT` macro.
# Commonly Asked Questions
## Why?
I prefer doing things like this before runtime with compile-time constants, instead of on runtime with JS variables.
## Are you insane?
Yeah, probably.
## Why not just use a Regex?
I'm just #special like that.
## Is this production ready?
No.

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

@ -0,0 +1,20 @@
{
"name": "rollup-plugin-preprocessor",
"version": "1.0.0",
"description": "A Rollup plugin that adds a C-like preprocessor to Javascript.",
"main": "src/main.js",
"type": "module",
"scripts": {
"test": "pushd test; rollup -c"
},
"keywords": ["rollup", "rollup-plugin", "c", "preprocessor"],
"author": "Ruthenic",
"license": "WTFPL",
"dependencies": {
"estree-walker": "^3.0.1",
"recast": "^0.21.2"
},
"peerDependencies": {
"rollup": "^2.78.1"
}
}

@ -0,0 +1,85 @@
lockfileVersion: 5.4
specifiers:
acorn: ^8.8.0
estree-util-attach-comments: ^2.1.0
estree-walker: ^3.0.1
recast: ^0.21.2
rollup: ^2.78.1
dependencies:
acorn: 8.8.0
estree-util-attach-comments: 2.1.0
estree-walker: 3.0.1
recast: 0.21.2
rollup: 2.78.1
packages:
/@types/estree/1.0.0:
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
dev: false
/acorn/8.8.0:
resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/ast-types/0.15.2:
resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==}
engines: {node: '>=4'}
dependencies:
tslib: 2.4.0
dev: false
/esprima/4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/estree-util-attach-comments/2.1.0:
resolution: {integrity: sha512-rJz6I4L0GaXYtHpoMScgDIwM0/Vwbu5shbMeER596rB2D1EWF6+Gj0e0UKzJPZrpoOc87+Q2kgVFHfjAymIqmw==}
dependencies:
'@types/estree': 1.0.0
dev: false
/estree-walker/3.0.1:
resolution: {integrity: sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g==}
dev: false
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: false
optional: true
/recast/0.21.2:
resolution: {integrity: sha512-jUR1+NtaBQdKDqBJ+qxwMm5zR8aLSNh268EfgAbY+EP4wcNEWb6hZFhFeYjaYanwgDahx5t47CH8db7X2NfKdQ==}
engines: {node: '>= 4'}
dependencies:
ast-types: 0.15.2
esprima: 4.0.1
source-map: 0.6.1
tslib: 2.4.0
dev: false
/rollup/2.78.1:
resolution: {integrity: sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.2
dev: false
/source-map/0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: false
/tslib/2.4.0:
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
dev: false

@ -0,0 +1,96 @@
import { walk } from 'estree-walker'
import recast from 'recast'
//my thoughts on this code are: na na na nani the fuck
export default function preprocess(opts) {
return {
name: "preprocess",
transform: {
order: 'pre',
handler(code) {
const state = {
failedIf: false
}
const parse = this.parse
const comments = []
const ast = recast.parse(code, {
parser: this
})
walk(ast, { //WALK CST FOR COMPTIME_VARS
enter(node, parent, prop, index) {
if (parent?.type === "MemberExpression" && parent?.property === node) {
if (state.failedIf) {
delete parent[prop]
}
return //ignore childs of objects ie console.log
} else if (node.type === "Identifier") {
if (opts.values) {
for (const i in opts.values) {
if (i === node.name) {
console.log(`Found comp-time var ${i} with value ${opts.values[i]}`)
const res = eval(`(${opts.values[i]})`)
if (typeof res === "string") {
parent[prop] = [ parse(`('${res}')`).body[0].expression ]
} else {
parent[prop] = [ parse(`(${res})`).body[0].expression ]
}
return
}
}
}
} else if (node.comments) {
node.comments.forEach((cmt, cidx) => {
for (const i in opts.transforms) {
if (cmt.value.startsWith(i)) {
console.log(`Found comp-time comment transformation ${i}`)
opts.transforms[i](cmt, node, cidx)
return
}
}
if (cmt.value.toUpperCase().startsWith("#IF ")) {
const vari = cmt.value.substring(4)
node.comments = []
if (opts.values[vari] === undefined) {
throw new Error("Cannot use undefined comp-time variable in #IF macro!")
} else {
const res = eval(`(${opts.values[vari]})`)
if (!!res) {
console.log("Broke into #IF macro")
} else {
console.log(`Unmet #IF for ${vari}`)
state.failedIf = true
}
}
} else if (cmt.value.toUpperCase().startsWith("#IFNOT ")) {
const vari = cmt.value.substring(7)
node.comments = []
if (opts.values[vari] === undefined) {
throw new Error("Cannot use undefined comp-time variable in #IFNOT macro!")
} else {
const res = eval(`(${opts.values[vari]})`)
if (!res) {
console.log("Broke into #IFNOT macro")
} else {
console.log(`Unmet #IFNOT for ${vari} at Line ${cmt.loc.start.line}:${cmt.loc.start.column}`)
state.failedIf = true
}
}
} else if (cmt.value.toUpperCase().startsWith("#END")) {
console.log("Broke out of macro")
node.comments = []
state.failedIf = false
}
})
} else {
if (state.failedIf) {
delete parent[prop]
}
}
}
})
return { code: recast.print(ast).code }
}
}
}
}

@ -0,0 +1,6 @@
console.log("Hello, world!");
console.log("#IF works");
console.log("#IFNOT works");
console.log("Hello, world!");
console.log(2);

@ -0,0 +1,21 @@
import preprocess from "../src/main.js"
export default {
input: "./test.js",
output: {
file: "out.js"
},
plugins: [
preprocess({
values: {
"COMPTIME_STR": "'Hello, world!'",
"COMPTIME_NUM": 2,
"IS_TRUE": 1,
"IS_FALSE": 0
},
transforms: {
"NONPROD": (node, parent, idx) => {parent.comments = []}
}
})
]
}

@ -0,0 +1,18 @@
console.log("Hello, world!")
//#IF IS_TRUE
console.log("#IF works")
//#END
//#IF IS_FALSE
console.log("#IF does not work (ignore the last one if this shows up)")
//#END
//#IfNoT IS_FALSE
console.log("#IFNOT works")
//#END
//#ifnot IS_TRUE
console.log("#IFNOT does not work (disregard prior)")
//#end
console.log(COMPTIME_STR)
console.log(COMPTIME_NUM)
Loading…
Cancel
Save