Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test/fixtures
test/macroFixtures
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
test/fixtures/**/output.js
test/macroFixtures/**/output.js
80 changes: 43 additions & 37 deletions lib/evaluateExpression.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/* eslint-disable no-console */
const { types: t, transformFileSync } = require('@babel/core');
const nodePath = require('path');

function evaluateExpression(path, expression, env) {
const evaluateFns = [
[t.isTaggedTemplateExpression, evaluateTaggedTemplateExpression],
[t.isTemplateLiteral, evaluateTemplateLiteralExpression],
[t.isLiteral, evaluateLiteral],
[t.isIdentifier, evaluateIdentifier],
[t.isMemberExpression, evaluateMemberExpression],
Expand All @@ -24,10 +27,10 @@ function evaluateExpression(path, expression, env) {
}

function evaluateLiteral(path, expression, env) {
if (expression.type !== 'TemplateLiteral') {
return expression.value;
}
return expression.value;
}

function evaluateTemplateLiteralExpression(path, expression, env) {
const quasis = expression.quasis;
const literals = [quasis[0].value.cooked];
const expressions = [];
Expand Down Expand Up @@ -68,15 +71,14 @@ function evaluateIdentifier(path, expression, env) {

const initPath = binding.path.get('init');
if (initPath.node) {
return evaluateExpression(initPath, initPath.node, env);
return evaluateExpression(path, initPath.node, env);
}
} else if (expression.name === 'undefined') {
return undefined;
}

throw new Error(
`babel-plugin-glsl: cannot resolve glslify() call, unknown or non-initialized identifier "${
expression.name
`babel-plugin-glsl: cannot resolve glslify() call, unknown or non-initialized identifier "${expression.name
}"`
);
}
Expand Down Expand Up @@ -109,8 +111,7 @@ function evaluateImport(importPath, env) {
exit(path) {
if (!exprToevaluate) {
throw new Error(
`babel-plugin-glsl: cannot resolve glslify() call, import "${
importPath.node.local.name
`babel-plugin-glsl: cannot resolve glslify() call, import "${importPath.node.local.name
}" not exported by "${src}"`
);
}
Expand All @@ -129,6 +130,7 @@ function evaluateMemberExpression(path, expression, env) {
const { property, object, computed } = expression;

if (['window', 'self', 'global', 'globalThis'].includes(object.name)) return expression;

const objectValue =
object.name === 'Math' ? Math : evaluateExpression(path, object, env);

Expand Down Expand Up @@ -166,13 +168,13 @@ function evaluateUnaryExpression(path, expression, env) {

// prettier-ignore
switch (expression.operator) {
case '+': return +value
case '-': return -value
case '!': return !value
case '~': return ~value
case 'typeof': return typeof value
case 'void': return void value
}
case '+': return +value
case '-': return -value
case '!': return !value
case '~': return ~value
case 'typeof': return typeof value
case 'void': return void value
}
throw new Error(
`babel-plugin-glsl: unsupported unary operator "${expression.operator}"`
);
Expand All @@ -186,40 +188,40 @@ function evaluateBinaryExpression(path, expression, env) {

// prettier-ignore
switch (expression.operator) {
case '+': return left + right
case '-': return left - right
case '*': return left * right
case '&': return left & right
case '/': return left / right
case '%': return left % right
case '|': return left | right
case '^': return left ^ right
case '||': return left || right
case '&&': return left && right
case '<<': return left << right
case '>>': return left >> right
case '>>>': return left >>> right
case '===': return left === right
case '!==': return left !== right
case '<': return left < right
case '>': return right < left
case '<=': return left <= right
case '>=': return left >= right
}
case '+': return left + right
case '-': return left - right
case '*': return left * right
case '&': return left & right
case '/': return left / right
case '%': return left % right
case '|': return left | right
case '^': return left ^ right
case '||': return left || right
case '&&': return left && right
case '<<': return left << right
case '>>': return left >> right
case '>>>': return left >>> right
case '===': return left === right
case '!==': return left !== right
case '<': return left < right
case '>': return right < left
case '<=': return left <= right
case '>=': return left >= right
}
throw new Error('babel-plugin-glsl: unsupported binary expression');
}

function evaluateArrayExpression(path, expression, env) {
return expression.elements.map(prop => evaluateExpression(path, prop, env));
}

function evaluateObjectExpression(path, expression, babel) {
function evaluateObjectExpression(path, expression, env) {
return expression.properties.reduce((result, property) => {
if (property.type !== 'ObjectProperty') {
throw new Error('babel-plugin-glsl: expected object property');
}

const value = evaluateExpression(path, property.value, babel);
const value = evaluateExpression(path, property.value, env);
const key = property.key;
if (key.type === 'Identifier') {
result[key.name] = value;
Expand All @@ -232,6 +234,10 @@ function evaluateObjectExpression(path, expression, babel) {
}, {});
}

function evaluateTaggedTemplateExpression(path, expression, env) {
return evaluateExpression(path, expression.node.quasi, env);
}

function isPrimitive(val) {
return val == null || /^[sbn]/.test(typeof val);
}
Expand Down
48 changes: 31 additions & 17 deletions lib/processGlslTag.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
const { dirname } = require('path');
const { readFileSync } = require('fs');
const { dirname, resolve } = require('path');
const { types: t } = require('@babel/core');
const evaluateExpression = require('./evaluateExpression');
const compile = require('./compile');

function processGlslTag(path, state) {
const cwd = dirname(state.filename);
const env = {
cwd,
};
const literal = evaluateExpression(path, path.node.quasi, env);
const env = { cwd };

if (t.isTemplateLiteral(literal)) {
literal.quasis = literal.quasis.map(quasi => {
quasi.value.raw = `\n${compile(quasi.value.raw, { basedir: cwd })}`;
return quasi;
});
path.replaceWith(literal);
return;
} else if (typeof literal === 'string') {
const result = compile(literal, { basedir: cwd });
if (
t.isCallExpression(path.node) &&
t.isStringLiteral(path.node.arguments[0])
) {
const filename = resolve(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to support resolving node_modules as well. Can you update this to use glsl-resolve ?

dirname(state.filename),
path.node.arguments[0].value
);
const contents = readFileSync(filename, "utf8");
const result = compile(contents, { basedir: dirname(filename) });
path.replaceWith(t.stringLiteral(result));
return;
} else {
throw new Error(
'babel-plugin-glsl: string template could not be evaluated'
);
const literal = evaluateExpression(path, path, env);
if (t.isTemplateLiteral(literal)) {
literal.quasis = literal.quasis.map(quasi => {
quasi.value.raw = `\n${compile(quasi.value.raw, { basedir: cwd })}`;
return quasi;
});
path.replaceWith(literal);
return;
} else if (typeof literal === 'string') {
const result = compile(literal, { basedir: cwd });
path.replaceWith(t.stringLiteral(result));
return;
}
}

throw new Error(
'babel-plugin-glsl: string template could not be evaluated'
);
}

module.exports = processGlslTag;
8 changes: 6 additions & 2 deletions macro.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
const { createMacro, MacroError } = require('babel-plugin-macros');
const processGlslTag = require('./lib/processGlslTag');

function glslifyMacro({ references, state }) {
function glslifyMacro({ references, state, babel }) {
const t = babel.types;
const { default: defaultImport = [] } = references;

defaultImport.forEach(referencePath => {
const path = referencePath.parentPath;
if (path.type === 'TaggedTemplateExpression') {
if (
(t.isCallExpression(path.node) &&
t.isStringLiteral(path.node.arguments[0])) ||
t.isTaggedTemplateExpression(path.node)) {
try {
processGlslTag(path, state);
} catch (e) {
Expand Down
8 changes: 8 additions & 0 deletions test/macro.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,13 @@ pluginTester({
`,
output: '"\\nvoid main () {\\n gl_FragColor = vec4(1, 0, 0, 1);\\n}";',
},
{
code: `
import glsl from '../macro';

glsl("./macroFixtures/externalFile/myshader.frag");
`,
output: '"#define E 2.718281828459045\\n#define PI 3.141592653589793\\n\\nvoid main () {\\n gl_FragColor = vec4(vec3(1.,0.,0.), 1);\\n}\\n";',
},
],
});
3 changes: 3 additions & 0 deletions test/macroFixtures/externalFile/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import glsl from 'glslify';

glsl("./myshader.frag");
2 changes: 2 additions & 0 deletions test/macroFixtures/externalFile/defines.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define E 2.718281828459045
#define PI 3.141592653589793
4 changes: 4 additions & 0 deletions test/macroFixtures/externalFile/myshader.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma glslify: import(./defines)
void main () {
gl_FragColor = vec4(#ff0000, 1);
}
1 change: 1 addition & 0 deletions test/macroFixtures/externalFile/output.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions test/macroFixtures/externalFile/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"glslify": {
"transform": [
"glslify-hex",
"glslify-import"
]
}
}