🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

glsl-modules

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

glsl-modules - npm Package Compare versions

Comparing version
0.3.0
to
0.4.0
+22
dist/core-system/module-content/base-entity.d.ts
import { EntityDependency } from "./entity-dependency.js";
import { ModuleEntity } from "./types.js";
declare const entityTypes: readonly ["function", "variable", "struct", "define"];
export type EntityType = typeof entityTypes[number];
export declare abstract class BaseEntity {
readonly type: EntityType;
key: string;
id: string;
name: string;
path: string;
definition: string;
index: number;
dependencies: EntityDependency[];
constructor(name: string, path: string, index: number, definition: string);
getResolvedDefinition(idNameMap: Record<string, string>): string;
isDependentOn(candidate: ModuleEntity): boolean;
addDependencies(...dependencies: EntityDependency[]): void;
removeDependency(id: string): void;
protected abstract getDependencyTestString(): string;
determineDependencies(candidateDependencies: EntityDependency[]): void;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseEntity = void 0;
const entityTypes = ["function", "variable", "struct", "define"];
class BaseEntity {
constructor(name, path, index, definition) {
this.dependencies = [];
this.id = `${path}/${name}`;
this.key = this.id;
this.name = name;
this.path = path;
this.index = index;
this.definition = definition.trim();
}
getResolvedDefinition(idNameMap) {
let { definition, name, id, dependencies } = this;
const newName = idNameMap[id];
if (newName)
definition = definition.replace(new RegExp(`\\b${name}\\b`), newName);
for (const dependency of dependencies) {
const newDependencyName = idNameMap[dependency.id];
if (newDependencyName) {
definition = definition.replaceAll(new RegExp(`\\b${dependency.localName}\\b`, "g"), newDependencyName);
}
else if (dependency.alias) {
definition = definition.replaceAll(new RegExp(`\\b${dependency.alias}\\b`, "g"), dependency.name);
}
}
return `/* ${id} */\n` + definition;
}
isDependentOn(candidate) {
return this.dependencies.some((dependency) => dependency.id === candidate.id);
}
addDependencies(...dependencies) {
for (const dependency of dependencies) {
if (this.dependencies.find((d) => d.id === dependency.id))
return;
this.dependencies.push(dependency);
}
}
removeDependency(id) {
const index = this.dependencies.findIndex((d) => d.id === id);
if (index === -1)
return;
this.dependencies.splice(index, 1);
}
determineDependencies(candidateDependencies) {
const dependencyTestString = this.getDependencyTestString();
const dependencies = candidateDependencies
.filter((dependency) => dependency.isDependencyOf(dependencyTestString));
this.addDependencies(...dependencies);
}
}
exports.BaseEntity = BaseEntity;
import { Define } from "./define.js";
import { Func } from "./func.js";
import { Struct } from "./struct.js";
import { Variable } from "./variable.js";
export type ModuleEntity = Func | Define | Struct | Variable;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
import { DependencyGraph } from "../utils/topological-sort.js";
import { GLSLModule } from "./glsl-module.js";
import { ModuleEntity } from "./module-content/types.js";
export declare class Resolver {
module: GLSLModule;
allEntities: ModuleEntity[];
idToEntityMap: Record<string, ModuleEntity[]>;
constructor(module: GLSLModule);
createIdToEntityMap(): Record<string, ModuleEntity[]>;
resolve(): string;
createDependencyGraph(): DependencyGraph;
sortEntitiesByDependencyOrder(): void;
createNameCollisionMap(entities: ModuleEntity[]): Record<string, string>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Resolver = void 0;
const resolve_dependencies_js_1 = require("../utils/resolve-dependencies.js");
const topological_sort_js_1 = require("../utils/topological-sort.js");
class Resolver {
constructor(module) {
this.module = module;
const { entities, moduleContext } = module;
// Create array of entities in module and all of the dependencies
this.allEntities = entities
.concat((0, resolve_dependencies_js_1.resolveDependencies)(entities, moduleContext.libraries));
this.idToEntityMap = this.createIdToEntityMap();
}
createIdToEntityMap() {
return this.allEntities.reduce((map, entity) => {
var _a;
var _b;
((_a = map[_b = entity.id]) !== null && _a !== void 0 ? _a : (map[_b] = [])).push(entity);
return map;
}, {});
}
resolve() {
const { allEntities } = this;
const idToNewNameMap = this.createNameCollisionMap(allEntities);
this.sortEntitiesByDependencyOrder();
let resolvedCode = [this.module.unparsedCode.trim()]
.concat(allEntities.map((entity) => entity.getResolvedDefinition(idToNewNameMap)))
.join("\n\n")
// Make code slightly more readable by removing excessive spacing
.replace(/\n+\s*\n+/g, "\n\n");
return resolvedCode;
}
// Creates graph that describes dependency structure of entities.
// The graph is represented as an object mapping each id to a set containing its dependencies
createDependencyGraph() {
var _a;
var _b;
const { allEntities, idToEntityMap } = this;
const dependencyGraph = {};
for (const entity of allEntities) {
const dependencySet = (_a = dependencyGraph[_b = entity.key]) !== null && _a !== void 0 ? _a : (dependencyGraph[_b] = new Set());
for (const dependency of entity.dependencies) {
// Get all entities that are potential dependencies
const candidateEntities = idToEntityMap[dependency.id];
if (!candidateEntities)
debugger;
for (const candidate of candidateEntities) {
if (candidate.key === entity.key)
continue;
// If the candidate has entity as dependency, there is a
// dependency cycle -> only include candidates that come
// before it in module
const isCyclicDependency = candidate.dependencies.some((dep) => dep.id === entity.id);
// Dependency cycle between different modules not allowed
if (isCyclicDependency && candidate.path !== entity.path)
throw new Error(`Cyclic dependency between modules not allowed: ${candidate.id} and ${entity.id}`);
if (isCyclicDependency && candidate.index > entity.index)
continue;
dependencySet.add(candidate.key);
}
}
}
return dependencyGraph;
}
// Sorts the array of entities in the correct order, ensuring
// dependencies come before dependents
sortEntitiesByDependencyOrder() {
const dependencyGraph = this.createDependencyGraph();
const entityOrder = (0, topological_sort_js_1.topologicalSort)(dependencyGraph);
// Maps from id of entity to its position in the script
const keyToPositionMap = {};
for (let i = 0; i < entityOrder.length; i++) {
keyToPositionMap[entityOrder[i]] = i;
}
this.allEntities.sort((a, b) => keyToPositionMap[a.key] - keyToPositionMap[b.key]);
}
createNameCollisionMap(entities) {
var _a;
var _b;
const nameEntityIdsMap = {};
for (const entity of entities) {
((_a = nameEntityIdsMap[_b = entity.name]) !== null && _a !== void 0 ? _a : (nameEntityIdsMap[_b] = new Set())).add(entity.id);
}
const idToNewNameMap = {};
for (const [name, idSet] of Object.entries(nameEntityIdsMap)) {
if (idSet.size < 2)
continue; // Unique name
const separator = name.endsWith("_") ? "" : "_";
const ids = Array.from(idSet);
for (let i = 0; i < ids.length; i++) {
idToNewNameMap[ids[i]] = `${name}${separator}${i}`;
}
}
return idToNewNameMap;
}
}
exports.Resolver = Resolver;
+1
-2
import { GLSLModule } from "./glsl-module.js";
import { GLSLPlugin } from "./glsl-plugin.js";
import { ModuleEntity } from "./module-content/module-entity.js";
import { ModuleEntity } from "./module-content/types.js";
type LibraryStructure = {

@@ -27,5 +27,4 @@ [key: string]: LibraryStructure | GLSLModule | string;

getEntity(path: string, name: string, type: "import" | "ambient", originId: string): ModuleEntity[];
resolveDependencies(entity: ModuleEntity, seenIds?: Set<string>): ModuleEntity[];
addDependency(library: GLSLLibrary): this;
}
export {};

@@ -50,7 +50,6 @@ "use strict";

const module = this.modules[path];
if (!module)
throw new Error(`No module "${path}" in library ${this.name}`);
return module.getEntity({ name, type, originId });
}
resolveDependencies(entity, seenIds) {
return resolveDependenciesHelper(entity, this, seenIds !== null && seenIds !== void 0 ? seenIds : new Set());
}
addDependency(library) {

@@ -77,18 +76,1 @@ this.dependencies[library.name] = library;

}
function resolveDependenciesHelper(entity, library, seenIds) {
const entries = [];
for (const { id, path, name, type } of entity.dependencies) {
if (seenIds.has(id))
continue;
seenIds.add(id);
const libraryName = GLSLLibrary.extractLibraryNameFromPath(path);
const dependencyLibrary = libraryName === library.name ? library : library.dependencies[libraryName];
const exportedEntities = dependencyLibrary.getEntity(path, name, type, entity.id);
entries.push(...exportedEntities);
for (const entry of exportedEntities) {
const dependencies = resolveDependenciesHelper(entry, dependencyLibrary, seenIds);
entries.push(...dependencies);
}
}
return entries;
}

@@ -20,6 +20,6 @@ import { Export, Import, ModuleEntity } from "./module-content/index.js";

unparsedCode: string;
isOutputModule: boolean;
isShaderModule: boolean;
moduleContext: ModuleContext;
pluginContext: PluginContext;
constructor(path: string, code: string, context: ModuleContext, isOutputModule?: boolean);
constructor(path: string, code: string, context: ModuleContext);
parse(code: string): GLSLParser;

@@ -26,0 +26,0 @@ applyPlugins(): void;

@@ -8,12 +8,12 @@ "use strict";

const resolve_dependencies_js_1 = require("../utils/resolve-dependencies.js");
const index_js_1 = require("../utils/index.js");
const remove_comments_js_1 = require("../utils/remove-comments.js");
const resolver_js_1 = require("./resolver.js");
class GLSLModule {
constructor(path, code, context, isOutputModule = false) {
constructor(path, code, context) {
this.entities = [];
this.imports = [];
this.exports = [];
this.isShaderModule = false;
this.path = path;
this.moduleContext = context;
this.isOutputModule = isOutputModule;
const parser = this.parse(code);

@@ -27,3 +27,3 @@ this.unparsedCode = parser.code;

continue;
code = plugin.preprocess(code, this.isOutputModule);
code = plugin.preprocess(code, this.isShaderModule);
}

@@ -40,7 +40,5 @@ const parser = new glsl_parser_js_1.GLSLParser(code, this.path).parseAll();

var _a;
const { path, isOutputModule, } = this;
const { plugins, libraries: dependencies } = this.moduleContext;
let importedEntities = (0, resolve_dependencies_js_1.resolveDependencies)(this.entities, dependencies);
// TODO Again, temporary solution
importedEntities = [...new Set(importedEntities)];
const { path, isShaderModule: isOutputModule, } = this;
const { plugins, libraries } = this.moduleContext;
let importedEntities = (0, resolve_dependencies_js_1.resolveDependencies)(this.entities, libraries);
const context = this.pluginContext = new glsl_plugin_js_1.PluginContext(path, this.entities, this.imports, importedEntities);

@@ -73,14 +71,3 @@ for (const plugin of plugins) {

resolve() {
let entities = this.entities
.concat((0, resolve_dependencies_js_1.resolveDependencies)(this.entities, this.moduleContext.libraries));
// TODO this is a temporary solution, resolveDependencies should not have duplicate entities to begin with
entities = [...new Set(entities)];
const idToNewNameMap = createNameCollisionMap(entities);
sortEntitiesByDependencyOrder(entities);
let resolvedCode = [this.unparsedCode.trim()]
.concat(entities.map((entity) => entity.getResolvedDefinition(idToNewNameMap)))
.join("\n\n");
// Make code slightly more readable by removing excessive spacing
resolvedCode = resolvedCode.replace(/\n+\s*\n+/g, "\n\n");
return resolvedCode;
return new resolver_js_1.Resolver(this).resolve();
}

@@ -103,69 +90,1 @@ validateExport(request) {

exports.GLSLModule = GLSLModule;
// Creates graph that describes dependency structure of entities.
// The graph is represented as an object mapping each id to a set containing its
// dependencies
function createDependencyGraph(entities) {
var _a;
var _b;
const dependencyGraph = {};
const idToEntityMap = entities.reduce((map, entity) => {
var _a;
var _b;
((_a = map[_b = entity.id]) !== null && _a !== void 0 ? _a : (map[_b] = [])).push(entity);
return map;
}, {});
for (const entity of entities) {
const dependencySet = (_a = dependencyGraph[_b = entity.key]) !== null && _a !== void 0 ? _a : (dependencyGraph[_b] = new Set());
for (const dependency of entity.dependencies) {
// Get all entities that are potential dependencies
const candidateEntities = idToEntityMap[dependency.id];
for (const candidate of candidateEntities) {
if (candidate.key === entity.key)
continue;
// If the candidate has entity as dependency, there is a
// dependency cycle -> only include candidates that come
// before it in module
const isCyclicDependency = candidate.dependencies.some((dep) => dep.id === entity.id);
// Dependency cycle between different modules not allowed
(0, index_js_1.assert)(!(isCyclicDependency && candidate.path !== entity.path), `Cyclic dependency between modules not allowed: ${candidate.id} and ${entity.id}`);
if (isCyclicDependency && candidate.index > entity.index)
continue;
dependencySet.add(candidate.key);
}
}
}
return dependencyGraph;
}
// Takes an array of entities and sorts it in the correct order, ensuring
// dependencies come before dependents
function sortEntitiesByDependencyOrder(entities) {
const dependencyGraph = createDependencyGraph(entities);
const entityOrder = (0, index_js_1.topologicalSort)(dependencyGraph);
// Maps from id of entity to its position in the script
const keyToPositionMap = {};
for (let i = 0; i < entityOrder.length; i++) {
keyToPositionMap[entityOrder[i]] = i;
}
entities.sort((a, b) => keyToPositionMap[a.key] - keyToPositionMap[b.key]);
}
// Creates a map from the ids of entities with name collisions to new names
function createNameCollisionMap(entities) {
var _a;
var _b;
const nameEntityIdsMap = {};
for (const entity of entities) {
const set = (_a = nameEntityIdsMap[_b = entity.name]) !== null && _a !== void 0 ? _a : (nameEntityIdsMap[_b] = new Set());
set.add(entity.id);
}
const idToNewNameMap = {};
for (const [name, idSet] of Object.entries(nameEntityIdsMap)) {
if (idSet.size < 2)
continue; // Unique name
const separator = name.endsWith("_") ? "" : "_";
const ids = [...idSet];
for (let i = 0; i < ids.length; i++) {
idToNewNameMap[ids[i]] = `${name}${separator}${i}`;
}
}
return idToNewNameMap;
}

@@ -34,2 +34,5 @@ "use strict";

const [signature, returnType, name, argsString] = match.groups;
// Special case layout(location = 0), which may be incorrectly captured
if (name === "layout")
continue;
const definition = this.code.slice(startIndex, endIndex);

@@ -117,9 +120,10 @@ const args = index_js_2.Argument.parseArgumentsString(argsString);

throw new Error(`Invalid export entry: ${entry}`);
const [qualifier, name, alias] = extractMatch.groups;
let [qualifier, name, alias] = extractMatch.groups;
if (alias) {
if (this.code.match(new RegExp(`\\b${alias}\\b`)) !== null)
throw new Error(`Export alias "${alias}" exists in same module`);
this.code = this.code.replaceAll(new RegExp(`\\b${name}\\b`, "g"), alias);
this.code = this.code.replace(new RegExp(`\\b${name}\\b`, "g"), alias);
name = alias;
}
if (qualifier && !index_js_2.exportQualifiers.some((q) => q === qualifier))
if (qualifier && !index_js_2.exportQualifiers.includes(qualifier))
throw new Error(`Invalid export qualifier "${qualifier}"`);

@@ -126,0 +130,0 @@ return new index_js_2.Export(name, qualifier);

@@ -24,3 +24,4 @@ import { Import, ModuleEntity } from "./module-content/index.js";

};
export type GLSLPluginFunction<A extends any[] = any[]> = (...args: A) => GLSLPlugin;
type GLSLPluginFunction<A extends any[] = any[]> = (...args: A) => GLSLPlugin;
export declare function definePlugin<A extends any[]>(pluginFunction: GLSLPluginFunction<A>): GLSLPluginFunction<A>;
export {};

@@ -24,3 +24,4 @@ "use strict";

const { libraries, plugins } = this;
const module = new glsl_module_js_1.GLSLModule("@output", code, { libraries, plugins }, true);
const module = new glsl_module_js_1.GLSLModule("@shader", code, { libraries, plugins });
module.isShaderModule = true;
module.applyPlugins();

@@ -27,0 +28,0 @@ return module.resolve();

@@ -1,5 +0,6 @@

import { ModuleEntity } from "./module-entity.js";
import { BaseEntity } from "./base-entity.js";
export declare const defineRegex: RegExp;
export declare class Define extends ModuleEntity {
export declare class Define extends BaseEntity {
readonly type = "define";
protected getDependencyTestString(): string;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Define = exports.defineRegex = void 0;
const module_entity_js_1 = require("./module-entity.js");
const base_entity_js_1 = require("./base-entity.js");
exports.defineRegex = /^ *(#define +(\w+(?:\([^\)]*\))?) +(.*))$/m;
const extractDefineRegex = /#define *([^ ]+)+ *([^ ]+)+/;
class Define extends module_entity_js_1.ModuleEntity {
class Define extends base_entity_js_1.BaseEntity {
constructor() {
super(...arguments);
this.type = "define";
}
getDependencyTestString() {

@@ -9,0 +13,0 @@ const [, , value] = this.definition.match(extractDefineRegex);

@@ -1,2 +0,2 @@

import { ModuleEntity } from "./module-entity.js";
import { BaseEntity } from "./base-entity.js";
export declare const functionSignatureRegex: RegExp;

@@ -11,3 +11,4 @@ export declare class Argument {

}
export declare class Func extends ModuleEntity {
export declare class Func extends BaseEntity {
readonly type = "function";
arguments: Argument[];

@@ -14,0 +15,0 @@ constructor(name: string, path: string, index: number, definition: string, args: Argument[]);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Func = exports.Argument = exports.functionSignatureRegex = void 0;
const module_entity_js_1 = require("./module-entity.js");
const base_entity_js_1 = require("./base-entity.js");
const regexes_js_1 = require("../../utils/regexes.js");
exports.functionSignatureRegex = /((\w+)\s+(\w+)\s*\(([^\)]*)\))(?![^{]*\})/;
exports.functionSignatureRegex = /((\w+)\s+(\w+)\s*\(([^\)]*)\))(?:\s*\{)/;
const plainArgumentExtractRegex = /(\w+)\s+(\w+)/;

@@ -31,5 +31,6 @@ class Argument {

exports.Argument = Argument;
class Func extends module_entity_js_1.ModuleEntity {
class Func extends base_entity_js_1.BaseEntity {
constructor(name, path, index, definition, args) {
super(name, path, index, definition);
this.type = "function";
this.arguments = args;

@@ -36,0 +37,0 @@ this.key = `${this.id}:${args.map(({ type }) => type).join(",")}`;

@@ -0,1 +1,2 @@

export * from "./base-entity.js";
export * from "./define.js";

@@ -5,5 +6,5 @@ export * from "./export.js";

export * from "./import.js";
export * from "./module-entity.js";
export * from "./struct.js";
export * from "./variable.js";
export * from "./entity-dependency.js";
export * from "./types.js";

@@ -17,2 +17,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./base-entity.js"), exports);
__exportStar(require("./define.js"), exports);

@@ -22,5 +23,5 @@ __exportStar(require("./export.js"), exports);

__exportStar(require("./import.js"), exports);
__exportStar(require("./module-entity.js"), exports);
__exportStar(require("./struct.js"), exports);
__exportStar(require("./variable.js"), exports);
__exportStar(require("./entity-dependency.js"), exports);
__exportStar(require("./types.js"), exports);
import { Argument } from "./func.js";
import { ModuleEntity } from "./module-entity.js";
import { BaseEntity } from "./base-entity.js";
export declare const structRegex: RegExp;
export declare class Struct extends ModuleEntity {
export declare class Struct extends BaseEntity {
readonly type = "struct";
arguments: Argument[];

@@ -6,0 +7,0 @@ constructor(name: string, path: string, index: number, definition: string, args: Argument[]);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Struct = exports.structRegex = void 0;
const module_entity_js_1 = require("./module-entity.js");
const base_entity_js_1 = require("./base-entity.js");
exports.structRegex = /^ *(struct\s+(\w+)\s+{([^}]+)}\s*;)/m;
const extractStructBodyRegex = /^[^{]*{([\s\S]*)}\s*;$/;
class Struct extends module_entity_js_1.ModuleEntity {
class Struct extends base_entity_js_1.BaseEntity {
constructor(name, path, index, definition, args) {
super(name, path, index, definition);
this.type = "struct";
this.arguments = args;

@@ -11,0 +12,0 @@ }

@@ -1,5 +0,6 @@

import { ModuleEntity } from "./module-entity.js";
import { BaseEntity } from "./base-entity.js";
export declare const variableRegex: RegExp;
export declare class Variable extends ModuleEntity {
export declare class Variable extends BaseEntity {
readonly type = "variable";
protected getDependencyTestString(): string;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Variable = exports.variableRegex = void 0;
const module_entity_js_1 = require("./module-entity.js");
const base_entity_js_1 = require("./base-entity.js");
exports.variableRegex = /\s*((?:const\s+)?(\w+)\s+(\w+)\s+=\s+(\S+)\s*;)(?![^{]*})/;
class Variable extends module_entity_js_1.ModuleEntity {
class Variable extends base_entity_js_1.BaseEntity {
constructor() {
super(...arguments);
this.type = "variable";
}
getDependencyTestString() {

@@ -8,0 +12,0 @@ const [, , type, , value] = this.definition.match(exports.variableRegex);

@@ -1,1 +0,1 @@

export { GLSLRegistry, GLSLLibrary, GLSLPlugin as GLSLPlugin, definePlugin as createPlugin, resolveGLSL } from "./core-system/index.js";
export { GLSLRegistry, GLSLLibrary, GLSLPlugin, definePlugin, resolveGLSL } from "./core-system/index.js";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveGLSL = exports.createPlugin = exports.GLSLLibrary = exports.GLSLRegistry = void 0;
exports.resolveGLSL = exports.definePlugin = exports.GLSLLibrary = exports.GLSLRegistry = void 0;
var index_js_1 = require("./core-system/index.js");
Object.defineProperty(exports, "GLSLRegistry", { enumerable: true, get: function () { return index_js_1.GLSLRegistry; } });
Object.defineProperty(exports, "GLSLLibrary", { enumerable: true, get: function () { return index_js_1.GLSLLibrary; } });
Object.defineProperty(exports, "createPlugin", { enumerable: true, get: function () { return index_js_1.definePlugin; } });
Object.defineProperty(exports, "definePlugin", { enumerable: true, get: function () { return index_js_1.definePlugin; } });
Object.defineProperty(exports, "resolveGLSL", { enumerable: true, get: function () { return index_js_1.resolveGLSL; } });

@@ -91,3 +91,3 @@ "use strict";

var _a, _b;
const unprocessedFunctionBlocks = [...functionBlocks];
const unprocessedFunctionBlocks = Array.from(functionBlocks);
const processedFunctionStrings = [];

@@ -94,0 +94,0 @@ while (unprocessedFunctionBlocks.length > 0) {

@@ -9,3 +9,2 @@ "use strict";

exports.cssColorsPlugin = cssColorsPlugin;
const assert_js_1 = require("../utils/assert.js");
const find_closing_index_js_1 = require("../utils/find-closing-index.js");

@@ -17,3 +16,3 @@ const match_iterator_js_1 = require("../utils/match-iterator.js");

"named": /\bcss-([a-z]+)\b/i,
"hex": /#(?:[0-9a-f]){3,8}/i,
"hex": /#(?:(?:[0-9a-z]{3,4})|(?:[0-9a-z]{2}){3,4})\b/i,
"rgb": /\brgba?\(/i,

@@ -28,3 +27,2 @@ "hsl": /\bhsla?\(/i,

};
const validHexLengths = [4, 5, 7, 9];
function cssColorsPlugin(options = {}) {

@@ -49,6 +47,5 @@ var _a;

const { selection, startIndex, endIndex } = match;
if (selection === "#def")
if (selection === "#define")
continue;
const { length } = selection;
(0, assert_js_1.assert)(validHexLengths.some((l) => l === length), `Invalid hex triplet ${match}`);
parsedColors.push({ selection, cssString: selection, hasAlpha: length === 5 || length === 9, startIndex, endIndex });

@@ -55,0 +52,0 @@ }

@@ -1,3 +0,2 @@

import { GLSLPlugin } from "../core-system/glsl-plugin.js";
export declare function destructuringPlugin(): GLSLPlugin;
export {};
/**

@@ -4,0 +3,0 @@ * Plugin that destructures struct fields into variables

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.destructuringPlugin = destructuringPlugin;
const func_js_1 = require("../core-system/module-content/func.js");
const match_iterator_js_1 = require("../utils/match-iterator.js");
// Work in progress!
const pluginId = "destructuring";

@@ -52,4 +52,4 @@ const destructureRegex = /\w+\s*{\s*([^}]+)\s*}\s*=\s*/;

var _a, _b, _c;
const destructures = [...(0, match_iterator_js_1.matchIterator)(code, destructureRegex)];
const forLoops = [...(0, match_iterator_js_1.matchIterator)(code, /\bfor\s*\(/)];
const destructures = Array.from((0, match_iterator_js_1.matchIterator)(code, destructureRegex));
const forLoops = Array.from((0, match_iterator_js_1.matchIterator)(code, /\bfor\s*\(/));
let destructureIndex = 0;

@@ -60,3 +60,3 @@ let forIndex = 0;

let rootBlock = newBlock(rootStart);
let blockQueue = [];
let blockStack = [];
let parentBlock = null;

@@ -78,3 +78,3 @@ let currentBlock = rootBlock;

if (parentBlock)
blockQueue.push(parentBlock);
blockStack.push(parentBlock);
parentBlock = currentBlock;

@@ -92,3 +92,3 @@ currentBlock = newBlock(newBlockIndex);

currentBlock = parentBlock;
parentBlock = (_c = blockQueue.pop()) !== null && _c !== void 0 ? _c : null;
parentBlock = (_c = blockStack.pop()) !== null && _c !== void 0 ? _c : null;
braceLevel--;

@@ -95,0 +95,0 @@ }

@@ -76,3 +76,3 @@ "use strict";

let entityIndex = Math.max(...moduleEntities.map((entity) => entity.index + entity.definition.length)) + 2;
let candidateEntities = [...moduleEntities];
let candidateEntities = Array.from(moduleEntities);
while (candidateEntities.length > 0) {

@@ -87,3 +87,3 @@ const candidateEntity = candidateEntities.pop();

const { definition } = candidateEntity;
for (const { id, localName } of [...candidateEntity.dependencies]) {
for (const { id, localName } of Array.from(candidateEntity.dependencies)) {
const higherOrderFunctions = (_a = memoizedHOFs[id]) !== null && _a !== void 0 ? _a : (memoizedHOFs[id] = findHigherOrderFunctions(context.getEntitiesById(id)));

@@ -90,0 +90,0 @@ for (const func of higherOrderFunctions) {

@@ -9,2 +9,1 @@ export * from "./find-closing-index.js";

export * from "./split-at-commas-outside-braces.js";
export * from "./assert.js";

@@ -25,2 +25,1 @@ "use strict";

__exportStar(require("./split-at-commas-outside-braces.js"), exports);
__exportStar(require("./assert.js"), exports);

@@ -5,20 +5,23 @@ "use strict";

const glsl_library_js_1 = require("../core-system/glsl-library.js");
// TODO make more efficient, now it resolves the same dependencies multiple times
function resolveDependencies(entities, libraries) {
let resolvedEntities = [];
const seenIds = new Set(entities.map(({ id }) => id));
const seenIds = new Set();
const stack = [];
for (const entity of entities) {
for (const { path, id, name, type } of entity.dependencies) {
if (seenIds.has(id))
continue;
const libraryName = glsl_library_js_1.GLSLLibrary.extractLibraryNameFromPath(path);
const library = libraries[libraryName];
if (!library)
throw new Error(`Library ${libraryName} missing`);
const importedEntities = library.getEntity(path, name, type, entity.id);
resolvedEntities.push(...importedEntities);
for (const entity of importedEntities) {
const dependencies = library.resolveDependencies(entity, seenIds);
resolvedEntities.push(...dependencies);
}
seenIds.add(entity.id);
for (const dependency of entity.dependencies)
stack.push({ dependency, dependentId: entity.id, libraries });
}
while (stack.length > 0) {
const { dependency, dependentId, libraries } = stack.pop();
const { path, id, name, type } = dependency;
if (seenIds.has(id))
continue;
seenIds.add(id);
const activeLibrary = libraries[glsl_library_js_1.GLSLLibrary.extractLibraryNameFromPath(path)];
const exportedEntities = activeLibrary.getEntity(path, name, type, dependentId);
for (const entity of exportedEntities) {
for (const dependency of entity.dependencies)
stack.push({ dependency, dependentId: entity.id, libraries: activeLibrary.dependencies });
resolvedEntities.push(entity);
}

@@ -25,0 +28,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.splitAtCommasOutsideBraces = splitAtCommasOutsideBraces;
// TODO try to find regex solution
function splitAtCommasOutsideBraces(input) {

@@ -6,0 +5,0 @@ const components = [];

{
"name": "glsl-modules",
"version": "0.3.0",
"version": "0.4.0",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.js"
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.js"
},
"./plugins": {
"types": "./dist/plugins/index.d.ts",
"import": "./dist/plugins/index.js",
"require": "./dist/plugins/index.js"
}
},
"./plugins": {
"types": "./dist/plugins/index.d.ts",
"import": "./dist/plugins/index.js",
"require": "./dist/plugins/index.js"
}
},
"files": ["./dist"],
"files": [
"./dist"
],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
"build": "tsc -p tsconfig.build.json",
"prepublishOnly": "npm run build",
"test": "vitest",
"test:watch": "vitest --watch",
"test:coverage": "vitest run --coverage"
},
"keywords": ["glsl", "shader", "preprocessor", "webgl", "modules", "plugin"],
"keywords": [
"glsl",
"shader",
"preprocessor",
"webgl",
"modules",
"plugin"
],
"author": "Mathias Isaksen <mathias@st4yho.me> (https://st4yho.me)",

@@ -32,4 +44,8 @@ "license": "MIT",

"devDependencies": {
"typescript": "^5.7.3"
"@types/node": "^24.2.1",
"@vitest/ui": "^3.2.4",
"playwright": "^1.55.0",
"typescript": "^5.7.3",
"vitest": "^3.2.4"
}
}

@@ -14,3 +14,3 @@ <div align="center">

Interested in seeing it in action and trying it out for yourself?
Check out the glsl-modules playground: https://glsl-modules.vercel.app
Check out the playground: https://glsl-modules.vercel.app

@@ -32,2 +32,3 @@ The library is still a work in progress, and the API is subject to change.

* [css-colors](#css-colors)
* [Current known limitations](#current-known-limitations)

@@ -41,3 +42,2 @@ ## Installation

## Examples

@@ -370,1 +370,18 @@ **Note**: The GLSL code snippets below are simplified, missing version directives and so on.

```
## Current known limitations
### Global #if, #else and #endif directives
`glsl-modules` currently does not handle global `#if`-`#else`-`#endif` blocks (that is, not inside a function definition).
This, for example, will not work:
```glsl
#if SOME_VALUE
float foo() { return 1.0; }
#else
float foo() { return 2.0; }
#endif
```
### Library name collisions
It is currently not possible to add multiple libraries with the same name to a registry, or as dependencies to a library.
This may be eventually solved by supporting aliases for library dependencies.
import { EntityDependency } from "./entity-dependency.js";
export declare abstract class ModuleEntity {
key: string;
id: string;
name: string;
path: string;
definition: string;
index: number;
dependencies: EntityDependency[];
pluginData: any[];
constructor(name: string, path: string, index: number, definition: string);
getKey(): string;
getResolvedDefinition(idNameMap: Record<string, string>): string;
isDependentOn(candidate: ModuleEntity): boolean;
addDependencies(...dependencies: EntityDependency[]): void;
removeDependency(id: string): void;
protected abstract getDependencyTestString(): string;
determineDependencies(candidateDependencies: EntityDependency[]): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleEntity = void 0;
class ModuleEntity {
constructor(name, path, index, definition) {
this.dependencies = [];
this.pluginData = [];
this.id = `${path}/${name}`;
this.key = this.id;
this.name = name;
this.path = path;
this.index = index;
this.definition = definition.trim();
}
getKey() { return this.id; }
getResolvedDefinition(idNameMap) {
let { definition, name, id, dependencies } = this;
const newName = idNameMap[id];
if (newName)
definition = definition.replace(new RegExp(`\\b${name}\\b`), newName);
for (const dependency of dependencies) {
const newDependencyName = idNameMap[dependency.id];
if (newDependencyName) {
definition = definition.replaceAll(new RegExp(`\\b${dependency.localName}\\b`, "g"), newDependencyName);
}
else if (dependency.alias) {
definition = definition.replaceAll(new RegExp(`\\b${dependency.alias}\\b`, "g"), dependency.name);
}
}
return `/* ${id} */\n` + definition;
}
isDependentOn(candidate) {
return this.dependencies.some((dependency) => dependency.id === candidate.id);
}
addDependencies(...dependencies) {
for (const dependency of dependencies) {
if (this.dependencies.find((d) => d.id === dependency.id))
return;
this.dependencies.push(dependency);
}
}
removeDependency(id) {
const index = this.dependencies.findIndex((d) => d.id === id);
if (index === -1)
return;
this.dependencies.splice(index, 1);
}
determineDependencies(candidateDependencies) {
const dependencyTestString = this.getDependencyTestString();
const dependencies = candidateDependencies
.filter((dependency) => dependency.isDependencyOf(dependencyTestString));
this.addDependencies(...dependencies);
}
}
exports.ModuleEntity = ModuleEntity;
export declare function assert(test: any, errorMessage: string): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.assert = assert;
function assert(test, errorMessage) {
if (!test)
throw new Error("Assertion failed:\n" + errorMessage);
}