-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dev-tools): add ts-transform-remove-glsl-comments (#455)
- Loading branch information
1 parent
43e2ec0
commit e877883
Showing
16 changed files
with
362 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
dist/ | ||
test-case-*.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
**/dist*/**/*.js | ||
test-case-*.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
modules/dev-tools/src/ts-plugins/ts-transform-remove-glsl-comments/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/** | ||
* TypeScript transform to remove comments and unnecessary white space from GLSL source. | ||
* A template string is considered GLSL source if: | ||
a) the file matches the pattern specified in the plugin config; or | ||
b) it is tagged as glsl`...` | ||
* Usage with ts-patch: | ||
{ | ||
"plugins": [ | ||
{ | ||
"transform": "ocular-dev-tools/ts-transform-remove-glsl-comments", | ||
"pattern": ["*.glsl.ts"] | ||
} | ||
] | ||
} | ||
*/ | ||
import * as path from 'path'; | ||
import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; | ||
import type {TransformerExtras, PluginConfig} from 'ts-patch'; | ||
import minimatch from 'minimatch'; | ||
|
||
// inline comment is only safe to remove if it's followed by a return (i.e. end of comment) | ||
const INLINE_COMMENT_REGEX = /\s*\/\/.*[\n\r]/g; | ||
const BLOCK_COMMENT_REGEX = /\s*\/\*(\*(?!\/)|[^*])*\*\//g; | ||
const WHITESPACE_REGEX = /\s*[\n\r]\s*/gm; | ||
const DEFAULT_PATTERNS = []; | ||
|
||
type RemoveGLSLCommentsPluginConfig = PluginConfig & { | ||
/** Glob patterns of shader files to include. */ | ||
pattern?: string[]; | ||
}; | ||
|
||
export default function ( | ||
program: Program, | ||
pluginConfig: RemoveGLSLCommentsPluginConfig, | ||
{ts}: TransformerExtras | ||
) { | ||
const {pattern = DEFAULT_PATTERNS} = pluginConfig; | ||
|
||
return (ctx: TransformationContext) => { | ||
const {factory} = ctx; | ||
|
||
return (sourceFile: SourceFile) => { | ||
const isShaderFile = matchFilePath(sourceFile.fileName, pattern); | ||
|
||
function replaceShaderString(node: Node): Node { | ||
if (ts.isNoSubstitutionTemplateLiteral(node)) { | ||
const text = node.rawText ?? ''; | ||
// Convert source text to string content | ||
const newText = filterShaderSource(text); | ||
if (newText === text) { | ||
return node; | ||
} | ||
return factory.createNoSubstitutionTemplateLiteral(newText, newText); | ||
} | ||
if (ts.isTemplateLiteralToken(node)) { | ||
const text = node.rawText ?? ''; | ||
const newText = filterShaderSource(text); | ||
if (newText === text) { | ||
return node; | ||
} | ||
if (ts.isTemplateHead(node)) { | ||
return factory.createTemplateHead(newText, newText); | ||
} | ||
if (ts.isTemplateMiddle(node)) { | ||
return factory.createTemplateMiddle(newText, newText); | ||
} | ||
if (ts.isTemplateTail(node)) { | ||
return factory.createTemplateTail(newText, newText); | ||
} | ||
return node; | ||
} | ||
return ts.visitEachChild(node, replaceShaderString, ctx); | ||
} | ||
|
||
function visit(node: Node): Node { | ||
if ( | ||
ts.isTaggedTemplateExpression(node) && | ||
// First child is the tag identifier | ||
node.getChildAt(0).getText() === 'glsl' | ||
) { | ||
// Strip the template tag | ||
return replaceShaderString(node.getChildAt(1)); | ||
} | ||
if (isShaderFile && ts.isTemplateLiteral(node)) { | ||
return replaceShaderString(node); | ||
} | ||
return ts.visitEachChild(node, visit, ctx); | ||
} | ||
return ts.visitNode(sourceFile, visit); | ||
}; | ||
}; | ||
} | ||
|
||
function matchFilePath(filePath: string, includePatterns: string[]): boolean { | ||
const relPath = path.relative(process.env.PWD ?? '', filePath); | ||
for (const pattern of includePatterns) { | ||
if (minimatch(relPath, pattern)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
function filterShaderSource(source: string): string { | ||
return source | ||
.replace(INLINE_COMMENT_REGEX, '\n') | ||
.replace(BLOCK_COMMENT_REGEX, '') | ||
.replace(WHITESPACE_REGEX, '\n'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/index.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import {fileURLToPath} from 'node:url'; | ||
|
||
import test from 'tape-promise/tape'; | ||
import {transpile, assertSourceEqual} from '../test-transformer.js'; | ||
// @ts-expect-error Aliased import, remapped to valid path in esm-loader | ||
import removeGLSLComments from 'ocular-dev-tools/ts-plugins/ts-transform-remove-glsl-comments'; | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
|
||
function loadSourceFromFile(fileName: string): string { | ||
return fs.readFileSync(path.join(__dirname, fileName), 'utf8'); | ||
} | ||
|
||
const testCases = [ | ||
{ | ||
title: 'no comments', | ||
fileName: 'test.glsl.ts', | ||
config: {pattern: ['**/*.glsl.ts']}, | ||
input: 'test-case-0.ts', | ||
output: 'test-case-0-expected.ts' | ||
}, | ||
{ | ||
title: 'remove comments from template literal', | ||
fileName: 'test.glsl.ts', | ||
config: {pattern: ['**/*.glsl.ts']}, | ||
input: 'test-case-1.ts', | ||
output: 'test-case-1-expected.ts' | ||
}, | ||
{ | ||
title: 'excluded by file name', | ||
fileName: 'test.ts', | ||
config: {}, | ||
input: 'test-case-1.ts', | ||
output: 'test-case-1.ts' | ||
}, | ||
{ | ||
title: 'included by template tag', | ||
fileName: 'test.ts', | ||
config: {}, | ||
input: 'test-case-2.ts', | ||
output: 'test-case-2-expected.ts' | ||
} | ||
]; | ||
|
||
test('ts-transform-remove-glsl-comments', (t) => { | ||
for (const testCase of testCases) { | ||
const result = transpile({ | ||
sourceFileName: testCase.fileName, | ||
source: loadSourceFromFile(testCase.input), | ||
transformer: removeGLSLComments, | ||
config: testCase.config | ||
}); | ||
const expected = loadSourceFromFile(testCase.output); | ||
|
||
t.is(assertSourceEqual(result, expected, {ignoreEmptyLines: false}), true, testCase.title); | ||
} | ||
|
||
t.end(); | ||
}); |
4 changes: 4 additions & 0 deletions
4
modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0-expected.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export function getTime() { | ||
// Template literal that is not shader | ||
return `The time is ${Date.now()}`; | ||
} |
4 changes: 4 additions & 0 deletions
4
modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-0.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export function getTime() { | ||
// Template literal that is not shader | ||
return `The time is ${Date.now()}`; | ||
} |
34 changes: 34 additions & 0 deletions
34
modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1-expected.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// Constants | ||
const COORDINATE_SYSTEM = { | ||
CARTESIAN: 0, | ||
LNGLAT: 1 | ||
}; | ||
const constantDefinitions = Object.keys(COORDINATE_SYSTEM) | ||
.map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) | ||
.join('\n'); | ||
// Vertex shader | ||
export const vs = `\ | ||
#version 300 es | ||
${constantDefinitions} | ||
in vec4 position; | ||
in vec4 color; | ||
uniform mat4 pMatrix; | ||
uniform mat4 mMatrix; | ||
uniform float opacity; | ||
out vec4 vColor; | ||
main() { | ||
gl_Position = pMatrix * mMatrix * position; | ||
vColor = vec4(color, color.a * opacity); | ||
} | ||
`; | ||
// Fragment shader | ||
export const fs = `\ | ||
#version 300 es | ||
in vec4 vColor; | ||
main() { | ||
if (vColor.a == 0.0) { | ||
discard; | ||
} | ||
gl_FragColor = vColor; | ||
} | ||
`; |
43 changes: 43 additions & 0 deletions
43
modules/dev-tools/test/ts-plugins/ts-transform-remove-glsl-comments/test-case-1.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Constants | ||
const COORDINATE_SYSTEM = { | ||
CARTESIAN: 0, | ||
LNGLAT: 1 | ||
}; | ||
const constantDefinitions = Object.keys(COORDINATE_SYSTEM) | ||
.map((key) => `const int COORDINATE_SYSTEM_${key} = ${COORDINATE_SYSTEM[key]};`) | ||
.join('\n'); | ||
// Vertex shader | ||
export const vs = `\ | ||
#version 300 es | ||
${constantDefinitions} | ||
in vec4 position; | ||
in vec4 color; | ||
uniform mat4 pMatrix; // Projection matrix | ||
uniform mat4 mMatrix; // Model matrix | ||
uniform float opacity; | ||
out vec4 vColor; | ||
main() { | ||
gl_Position = pMatrix * mMatrix * position; | ||
vColor = vec4(color, /* inline comment */ color.a * opacity); | ||
} | ||
`; | ||
// Fragment shader | ||
export const fs = `\ | ||
#version 300 es | ||
in vec4 vColor; | ||
main() { | ||
if (vColor.a == 0.0) { | ||
/* | ||
Remove transparent fragment | ||
*/ | ||
discard; | ||
} | ||
gl_FragColor = vColor; | ||
} | ||
`; |
Oops, something went wrong.