wesl 0.6.46 → 0.6.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +57 -1
- package/dist/index.js +101 -2
- package/package.json +2 -2
- package/src/BindIdents.ts +1 -1
- package/src/ClickableError.ts +1 -1
- package/src/discovery/FindUnboundIdents.ts +43 -0
- package/src/discovery/PackageNameUtils.ts +71 -0
- package/src/index.ts +2 -0
- package/src/test/ConditionLinking.test.ts +17 -1
- package/src/test/PackageNameUtils.test.ts +32 -0
package/dist/index.d.ts
CHANGED
|
@@ -924,6 +924,62 @@ declare function scopeToString(scope: Scope, indent?: number, shortIdents?: bool
|
|
|
924
924
|
declare function scopeToStringLong(scope: Scope): string;
|
|
925
925
|
declare function identToString(ident?: Ident): string;
|
|
926
926
|
//#endregion
|
|
927
|
+
//#region src/discovery/FindUnboundIdents.d.ts
|
|
928
|
+
/**
|
|
929
|
+
* Find unbound package references in library sources.
|
|
930
|
+
*
|
|
931
|
+
* Binds local references without following cross-package imports, revealing
|
|
932
|
+
* which external packages are referenced but not resolved.
|
|
933
|
+
*
|
|
934
|
+
* @param resolver - Module resolver that supports batch operations
|
|
935
|
+
* @returns Array of unbound module paths, each as an array of path segments
|
|
936
|
+
* (e.g., [['foo', 'bar', 'baz'], ['other', 'pkg']])
|
|
937
|
+
*/
|
|
938
|
+
declare function findUnboundIdents(resolver: BatchModuleResolver): string[][];
|
|
939
|
+
//#endregion
|
|
940
|
+
//#region src/discovery/PackageNameUtils.d.ts
|
|
941
|
+
/** Package name sanitization for WESL.
|
|
942
|
+
*
|
|
943
|
+
* Converts typical npm package names to WGSL-safe identifiers using double-underscore encoding.
|
|
944
|
+
* NPM package names can contain `@`, `/`, and `-`, which are not allowed in WGSL identifiers.
|
|
945
|
+
*
|
|
946
|
+
* ## Encoding Scheme
|
|
947
|
+
*
|
|
948
|
+
* ```
|
|
949
|
+
* @ ==> (remove)
|
|
950
|
+
* / ==> __ (double underscore)
|
|
951
|
+
* - ==> _ (single underscore)
|
|
952
|
+
* ```
|
|
953
|
+
*
|
|
954
|
+
* ## Forward Mapping (npm ==> WGSL identifier)
|
|
955
|
+
*
|
|
956
|
+
* ```
|
|
957
|
+
* my_package ==> my_package
|
|
958
|
+
* random-wgsl ==> random_wgsl
|
|
959
|
+
* @scope/my-pkg ==> scope__my_pkg
|
|
960
|
+
* ```
|
|
961
|
+
*
|
|
962
|
+
* ## Reverse Mapping (WGSL identifier ==> npm package)
|
|
963
|
+
*
|
|
964
|
+
* ```
|
|
965
|
+
* scope__my_pkg ==> try: @scope/my_pkg, @scope/my-pkg
|
|
966
|
+
* random_wgsl ==> try: random_wgsl, random-wgsl
|
|
967
|
+
* ```
|
|
968
|
+
*/
|
|
969
|
+
/** Convert npm package name to WGSL-safe identifier using double-underscore encoding. */
|
|
970
|
+
declare function sanitizePackageName(npmName: string): string;
|
|
971
|
+
/** Generate npm package name variations from sanitized WESL identifier.
|
|
972
|
+
*
|
|
973
|
+
* Uses double-underscore encoding to distinguish scoped vs unscoped packages:
|
|
974
|
+
* - Has __ → scoped package (try @scope/pkg variants)
|
|
975
|
+
* - No __ → unscoped package (try pkg variants)
|
|
976
|
+
*
|
|
977
|
+
* Examples:
|
|
978
|
+
* "lygia__shader_utils" → ["@lygia/shader_utils", "@lygia/shader-utils"]
|
|
979
|
+
* "random_wgsl" → ["random_wgsl", "random-wgsl"]
|
|
980
|
+
*/
|
|
981
|
+
declare function npmNameVariations(sanitizedPath: string): Generator<string>;
|
|
982
|
+
//#endregion
|
|
927
983
|
//#region src/PathUtil.d.ts
|
|
928
984
|
/** simplistic path manipulation utilities */
|
|
929
985
|
/** return path with ./ and foo/.. elements removed */
|
|
@@ -1063,4 +1119,4 @@ declare function offsetToLineNumber(offset: number, text: string): [lineNum: num
|
|
|
1063
1119
|
*/
|
|
1064
1120
|
declare function errorHighlight(source: string, span: Span): [string, string];
|
|
1065
1121
|
//#endregion
|
|
1066
|
-
export { AbstractElem, AbstractElemBase, AliasElem, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BindingStructElem, BoundAndTransformed, BuiltinAttribute, BundleResolver, ComponentExpression, ComponentMemberExpression, CompositeResolver, Conditions, ConstAssertElem, ConstElem, ContainerElem, DeclIdent, DeclIdentElem, DeclarationElem, DiagnosticAttribute, DiagnosticDirective, DirectiveElem, DirectiveVariant, ElemWithAttributes, ElemWithContentsBase, ElifAttribute, ElseAttribute, EmittableElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, ManglerFn, ModuleElem, ModuleResolver, NameElem, OverrideElem, ParenthesizedExpression, PartialScope, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, Scope, SimpleMemberRef, SrcModule, StableState, StandardAttribute, StatementElem, StructElem, StructMemberElem, StuffElem, SwitchClauseElem, SyntheticElem, TerminalElem, TextElem, TransformedAST, TranslateTimeExpressionElem, TranslateTimeFeature, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnknownExpressionElem, VarElem, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, blankWeslParseState, childIdent, childScope, containsScope, debugContentsToString, emptyScope, errorHighlight, filterMap, findMap, findRefsToBindingStructs, findValidRootDecls, flatImports, groupBy, grouped, identToString, isGlobal, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, multiKeySet, nextIdentId, noSuffix, normalize, normalizeModuleName, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, scan, scopeToString, scopeToStringLong, syntheticWeslParseState, transformBindingReference, transformBindingStruct, underscoreMangle };
|
|
1122
|
+
export { AbstractElem, AbstractElemBase, AliasElem, Attribute, AttributeElem, BatchModuleResolver, BinaryExpression, BinaryOperator, BindIdentsParams, BindResults, BindingAST, BindingStructElem, BoundAndTransformed, BuiltinAttribute, BundleResolver, ComponentExpression, ComponentMemberExpression, CompositeResolver, Conditions, ConstAssertElem, ConstElem, ContainerElem, DeclIdent, DeclIdentElem, DeclarationElem, DiagnosticAttribute, DiagnosticDirective, DirectiveElem, DirectiveVariant, ElemWithAttributes, ElemWithContentsBase, ElifAttribute, ElseAttribute, EmittableElem, EnableDirective, ExpressionElem, ExtendedGPUValidationError, FnElem, FnParamElem, FunctionCallExpression, GlobalDeclarationElem, GlobalVarElem, GrammarElem, HasAttributes, Ident, IfAttribute, ImportCollection, ImportElem, ImportItem, ImportSegment, ImportStatement, InterpolateAttribute, LetElem, LexicalScope, LinkConfig, LinkParams, LinkRegistryParams, LinkedWesl, LinkerTransform, Literal, LiveDecls, ManglerFn, ModuleElem, ModuleResolver, NameElem, OverrideElem, ParenthesizedExpression, PartialScope, RecordResolver, RecordResolverOptions, RefIdent, RefIdentElem, RequiresDirective, Scope, SimpleMemberRef, SrcModule, StableState, StandardAttribute, StatementElem, StructElem, StructMemberElem, StuffElem, SwitchClauseElem, SyntheticElem, TerminalElem, TextElem, TransformedAST, TranslateTimeExpressionElem, TranslateTimeFeature, TypeRefElem, TypeTemplateParameter, TypedDeclElem, UnaryExpression, UnaryOperator, UnknownExpressionElem, VarElem, VirtualLibrary, VirtualLibraryFn, VirtualLibrarySet, WeslAST, WeslBundle, WeslDevice, WeslGPUCompilationInfo, WeslGPUCompilationMessage, WeslJsPlugin, WeslParseContext, WeslParseError, WeslParseState, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, blankWeslParseState, childIdent, childScope, containsScope, debugContentsToString, emptyScope, errorHighlight, filterMap, findMap, findRefsToBindingStructs, findUnboundIdents, findValidRootDecls, flatImports, groupBy, grouped, identToString, isGlobal, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, multiKeySet, nextIdentId, noSuffix, normalize, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, sanitizePackageName, scan, scopeToString, scopeToStringLong, syntheticWeslParseState, transformBindingReference, transformBindingStruct, underscoreMangle };
|
package/dist/index.js
CHANGED
|
@@ -2530,7 +2530,7 @@ function findQualifiedImport(refIdent$1, resolver, conditions, virtuals, unbound
|
|
|
2530
2530
|
const identParts = refIdent$1.originalName.split("::");
|
|
2531
2531
|
const modulePathParts = matchingImport(identParts, flatImps) ?? qualifiedIdent(identParts);
|
|
2532
2532
|
if (!modulePathParts) {
|
|
2533
|
-
if (unbound) unbound.push(identParts);
|
|
2533
|
+
if (unbound && !stdWgsl(refIdent$1.originalName)) unbound.push(identParts);
|
|
2534
2534
|
return;
|
|
2535
2535
|
}
|
|
2536
2536
|
const result = findExport(modulePathParts, refIdent$1.ast.srcModule, resolver, conditions, virtuals);
|
|
@@ -2623,6 +2623,105 @@ function collectDecls(scope, found) {
|
|
|
2623
2623
|
else if (item.kind === "partial") collectDecls(item, found);
|
|
2624
2624
|
}
|
|
2625
2625
|
|
|
2626
|
+
//#endregion
|
|
2627
|
+
//#region src/discovery/FindUnboundIdents.ts
|
|
2628
|
+
/**
|
|
2629
|
+
* Find unbound package references in library sources.
|
|
2630
|
+
*
|
|
2631
|
+
* Binds local references without following cross-package imports, revealing
|
|
2632
|
+
* which external packages are referenced but not resolved.
|
|
2633
|
+
*
|
|
2634
|
+
* @param resolver - Module resolver that supports batch operations
|
|
2635
|
+
* @returns Array of unbound module paths, each as an array of path segments
|
|
2636
|
+
* (e.g., [['foo', 'bar', 'baz'], ['other', 'pkg']])
|
|
2637
|
+
*/
|
|
2638
|
+
function findUnboundIdents(resolver) {
|
|
2639
|
+
const bindContext = {
|
|
2640
|
+
resolver,
|
|
2641
|
+
conditions: {},
|
|
2642
|
+
knownDecls: /* @__PURE__ */ new Set(),
|
|
2643
|
+
foundScopes: /* @__PURE__ */ new Set(),
|
|
2644
|
+
globalNames: /* @__PURE__ */ new Set(),
|
|
2645
|
+
globalStatements: /* @__PURE__ */ new Map(),
|
|
2646
|
+
mangler: minimalMangle,
|
|
2647
|
+
unbound: [],
|
|
2648
|
+
dontFollowDecls: true
|
|
2649
|
+
};
|
|
2650
|
+
for (const [_modulePath, ast] of resolver.allModules()) {
|
|
2651
|
+
const declEntries = findValidRootDecls(ast.rootScope, {}).map((d) => [d.originalName, d]);
|
|
2652
|
+
const liveDecls = {
|
|
2653
|
+
decls: new Map(declEntries),
|
|
2654
|
+
parent: null
|
|
2655
|
+
};
|
|
2656
|
+
bindIdentsRecursive(ast.rootScope, bindContext, liveDecls, true);
|
|
2657
|
+
}
|
|
2658
|
+
return bindContext.unbound;
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
//#endregion
|
|
2662
|
+
//#region src/discovery/PackageNameUtils.ts
|
|
2663
|
+
/** Package name sanitization for WESL.
|
|
2664
|
+
*
|
|
2665
|
+
* Converts typical npm package names to WGSL-safe identifiers using double-underscore encoding.
|
|
2666
|
+
* NPM package names can contain `@`, `/`, and `-`, which are not allowed in WGSL identifiers.
|
|
2667
|
+
*
|
|
2668
|
+
* ## Encoding Scheme
|
|
2669
|
+
*
|
|
2670
|
+
* ```
|
|
2671
|
+
* @ ==> (remove)
|
|
2672
|
+
* / ==> __ (double underscore)
|
|
2673
|
+
* - ==> _ (single underscore)
|
|
2674
|
+
* ```
|
|
2675
|
+
*
|
|
2676
|
+
* ## Forward Mapping (npm ==> WGSL identifier)
|
|
2677
|
+
*
|
|
2678
|
+
* ```
|
|
2679
|
+
* my_package ==> my_package
|
|
2680
|
+
* random-wgsl ==> random_wgsl
|
|
2681
|
+
* @scope/my-pkg ==> scope__my_pkg
|
|
2682
|
+
* ```
|
|
2683
|
+
*
|
|
2684
|
+
* ## Reverse Mapping (WGSL identifier ==> npm package)
|
|
2685
|
+
*
|
|
2686
|
+
* ```
|
|
2687
|
+
* scope__my_pkg ==> try: @scope/my_pkg, @scope/my-pkg
|
|
2688
|
+
* random_wgsl ==> try: random_wgsl, random-wgsl
|
|
2689
|
+
* ```
|
|
2690
|
+
*/
|
|
2691
|
+
/** Convert npm package name to WGSL-safe identifier using double-underscore encoding. */
|
|
2692
|
+
function sanitizePackageName(npmName) {
|
|
2693
|
+
return npmName.replace(/^@/, "").replaceAll("/", "__").replaceAll("-", "_");
|
|
2694
|
+
}
|
|
2695
|
+
/** Generate npm package name variations from sanitized WESL identifier.
|
|
2696
|
+
*
|
|
2697
|
+
* Uses double-underscore encoding to distinguish scoped vs unscoped packages:
|
|
2698
|
+
* - Has __ → scoped package (try @scope/pkg variants)
|
|
2699
|
+
* - No __ → unscoped package (try pkg variants)
|
|
2700
|
+
*
|
|
2701
|
+
* Examples:
|
|
2702
|
+
* "lygia__shader_utils" → ["@lygia/shader_utils", "@lygia/shader-utils"]
|
|
2703
|
+
* "random_wgsl" → ["random_wgsl", "random-wgsl"]
|
|
2704
|
+
*/
|
|
2705
|
+
function* npmNameVariations(sanitizedPath) {
|
|
2706
|
+
const [pkg, sub] = breakAt(sanitizedPath, "/");
|
|
2707
|
+
let pkgName = pkg;
|
|
2708
|
+
let scopePrefix = "";
|
|
2709
|
+
if (pkg.includes("__")) {
|
|
2710
|
+
const [scope, ...rest] = pkg.split("__");
|
|
2711
|
+
pkgName = rest.join("__");
|
|
2712
|
+
scopePrefix = `@${scope}/`;
|
|
2713
|
+
}
|
|
2714
|
+
yield `${scopePrefix}${pkgName}${sub}`;
|
|
2715
|
+
yield `${scopePrefix}${pkgName.replaceAll("_", "-")}${sub}`;
|
|
2716
|
+
}
|
|
2717
|
+
/** Break string at first occurrence of delimiter.
|
|
2718
|
+
* @returns [before, after] where after includes the delimiter */
|
|
2719
|
+
function breakAt(str, delimiter) {
|
|
2720
|
+
const index = str.indexOf(delimiter);
|
|
2721
|
+
if (index === -1) return [str, ""];
|
|
2722
|
+
return [str.slice(0, index), str.slice(index)];
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2626
2725
|
//#endregion
|
|
2627
2726
|
//#region src/LinkedWesl.ts
|
|
2628
2727
|
/**
|
|
@@ -3387,4 +3486,4 @@ function makeWeslDevice(device) {
|
|
|
3387
3486
|
}
|
|
3388
3487
|
|
|
3389
3488
|
//#endregion
|
|
3390
|
-
export { BundleResolver, CompositeResolver, LinkedWesl, RecordResolver, WeslParseError, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, blankWeslParseState, childIdent, childScope, containsScope, debugContentsToString, emptyScope, errorHighlight, filterMap, findMap, findRefsToBindingStructs, findValidRootDecls, flatImports, groupBy, grouped, identToString, isGlobal, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, multiKeySet, nextIdentId, noSuffix, normalize, normalizeModuleName, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, scan, scopeToString, scopeToStringLong, syntheticWeslParseState, transformBindingReference, transformBindingStruct, underscoreMangle };
|
|
3489
|
+
export { BundleResolver, CompositeResolver, LinkedWesl, RecordResolver, WeslParseError, WeslStream, _linkSync, astToString, attributeToString, bindAndTransform, bindIdents, bindIdentsRecursive, bindingStructsPlugin, blankWeslParseState, childIdent, childScope, containsScope, debugContentsToString, emptyScope, errorHighlight, filterMap, findMap, findRefsToBindingStructs, findUnboundIdents, findValidRootDecls, flatImports, groupBy, grouped, identToString, isGlobal, last, lengthPrefixMangle, link, linkRegistry, liveDeclsToString, lowerBindingStructs, makeLiveDecls, makeWeslDevice, mapForward, mapValues, markBindingStructs, markEntryTypes, mergeScope, minimalMangle, minimallyMangledName, multiKeySet, nextIdentId, noSuffix, normalize, normalizeModuleName, npmNameVariations, offsetToLineNumber, overlapTail, parseSrcModule, partition, publicDecl, replaceWords, requestWeslDevice, resetScopeIds, sanitizePackageName, scan, scopeToString, scopeToStringLong, syntheticWeslParseState, transformBindingReference, transformBindingStruct, underscoreMangle };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wesl",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"mini-parse": "0.6.
|
|
18
|
+
"mini-parse": "0.6.41"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/brotli": "^1.3.4",
|
package/src/BindIdents.ts
CHANGED
|
@@ -434,7 +434,7 @@ function findQualifiedImport(
|
|
|
434
434
|
matchingImport(identParts, flatImps) ?? qualifiedIdent(identParts);
|
|
435
435
|
|
|
436
436
|
if (!modulePathParts) {
|
|
437
|
-
if (unbound) unbound.push(identParts);
|
|
437
|
+
if (unbound && !stdWgsl(refIdent.originalName)) unbound.push(identParts);
|
|
438
438
|
return undefined;
|
|
439
439
|
}
|
|
440
440
|
|
package/src/ClickableError.ts
CHANGED
|
@@ -75,7 +75,7 @@ export function throwClickableError(params: ClickableErrorParams): void {
|
|
|
75
75
|
let oldLimit = 0;
|
|
76
76
|
// Supported on Chrome https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stackTraceLimit
|
|
77
77
|
if ("stackTraceLimit" in Error) {
|
|
78
|
-
oldLimit = Error.stackTraceLimit;
|
|
78
|
+
oldLimit = Error.stackTraceLimit as number;
|
|
79
79
|
Error.stackTraceLimit = 1;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AbstractElem } from "../AbstractElems.ts";
|
|
2
|
+
import {
|
|
3
|
+
bindIdentsRecursive,
|
|
4
|
+
type EmittableElem,
|
|
5
|
+
findValidRootDecls,
|
|
6
|
+
} from "../BindIdents.ts";
|
|
7
|
+
import type { LiveDecls } from "../LiveDeclarations.ts";
|
|
8
|
+
import { minimalMangle } from "../Mangler.ts";
|
|
9
|
+
import type { BatchModuleResolver } from "../ModuleResolver.ts";
|
|
10
|
+
import type { DeclIdent, Scope } from "../Scope.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Find unbound package references in library sources.
|
|
14
|
+
*
|
|
15
|
+
* Binds local references without following cross-package imports, revealing
|
|
16
|
+
* which external packages are referenced but not resolved.
|
|
17
|
+
*
|
|
18
|
+
* @param resolver - Module resolver that supports batch operations
|
|
19
|
+
* @returns Array of unbound module paths, each as an array of path segments
|
|
20
|
+
* (e.g., [['foo', 'bar', 'baz'], ['other', 'pkg']])
|
|
21
|
+
*/
|
|
22
|
+
export function findUnboundIdents(resolver: BatchModuleResolver): string[][] {
|
|
23
|
+
const bindContext = {
|
|
24
|
+
resolver,
|
|
25
|
+
conditions: {},
|
|
26
|
+
knownDecls: new Set<DeclIdent>(),
|
|
27
|
+
foundScopes: new Set<Scope>(),
|
|
28
|
+
globalNames: new Set<string>(),
|
|
29
|
+
globalStatements: new Map<AbstractElem, EmittableElem>(),
|
|
30
|
+
mangler: minimalMangle,
|
|
31
|
+
unbound: [] as string[][],
|
|
32
|
+
dontFollowDecls: true,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
for (const [_modulePath, ast] of resolver.allModules()) {
|
|
36
|
+
const rootDecls = findValidRootDecls(ast.rootScope, {});
|
|
37
|
+
const declEntries = rootDecls.map(d => [d.originalName, d] as const);
|
|
38
|
+
const liveDecls: LiveDecls = { decls: new Map(declEntries), parent: null };
|
|
39
|
+
bindIdentsRecursive(ast.rootScope, bindContext, liveDecls, true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return bindContext.unbound;
|
|
43
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Package name sanitization for WESL.
|
|
2
|
+
*
|
|
3
|
+
* Converts typical npm package names to WGSL-safe identifiers using double-underscore encoding.
|
|
4
|
+
* NPM package names can contain `@`, `/`, and `-`, which are not allowed in WGSL identifiers.
|
|
5
|
+
*
|
|
6
|
+
* ## Encoding Scheme
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* @ ==> (remove)
|
|
10
|
+
* / ==> __ (double underscore)
|
|
11
|
+
* - ==> _ (single underscore)
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* ## Forward Mapping (npm ==> WGSL identifier)
|
|
15
|
+
*
|
|
16
|
+
* ```
|
|
17
|
+
* my_package ==> my_package
|
|
18
|
+
* random-wgsl ==> random_wgsl
|
|
19
|
+
* @scope/my-pkg ==> scope__my_pkg
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ## Reverse Mapping (WGSL identifier ==> npm package)
|
|
23
|
+
*
|
|
24
|
+
* ```
|
|
25
|
+
* scope__my_pkg ==> try: @scope/my_pkg, @scope/my-pkg
|
|
26
|
+
* random_wgsl ==> try: random_wgsl, random-wgsl
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** Convert npm package name to WGSL-safe identifier using double-underscore encoding. */
|
|
31
|
+
export function sanitizePackageName(npmName: string): string {
|
|
32
|
+
return npmName
|
|
33
|
+
.replace(/^@/, "") // Remove @ prefix
|
|
34
|
+
.replaceAll("/", "__") // Replace / with __ (double underscore)
|
|
35
|
+
.replaceAll("-", "_"); // Replace - with _ (single underscore)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Generate npm package name variations from sanitized WESL identifier.
|
|
39
|
+
*
|
|
40
|
+
* Uses double-underscore encoding to distinguish scoped vs unscoped packages:
|
|
41
|
+
* - Has __ → scoped package (try @scope/pkg variants)
|
|
42
|
+
* - No __ → unscoped package (try pkg variants)
|
|
43
|
+
*
|
|
44
|
+
* Examples:
|
|
45
|
+
* "lygia__shader_utils" → ["@lygia/shader_utils", "@lygia/shader-utils"]
|
|
46
|
+
* "random_wgsl" → ["random_wgsl", "random-wgsl"]
|
|
47
|
+
*/
|
|
48
|
+
export function* npmNameVariations(sanitizedPath: string): Generator<string> {
|
|
49
|
+
const [pkg, sub] = breakAt(sanitizedPath, "/");
|
|
50
|
+
|
|
51
|
+
let pkgName = pkg;
|
|
52
|
+
let scopePrefix = "";
|
|
53
|
+
|
|
54
|
+
if (pkg.includes("__")) {
|
|
55
|
+
// presume a scoped npm package (@scope/pkg)
|
|
56
|
+
const [scope, ...rest] = pkg.split("__");
|
|
57
|
+
pkgName = rest.join("__"); // Rejoin in case of __ in package name (rare)
|
|
58
|
+
scopePrefix = `@${scope}/`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
yield `${scopePrefix}${pkgName}${sub}`;
|
|
62
|
+
yield `${scopePrefix}${pkgName.replaceAll("_", "-")}${sub}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Break string at first occurrence of delimiter.
|
|
66
|
+
* @returns [before, after] where after includes the delimiter */
|
|
67
|
+
function breakAt(str: string, delimiter: string): [string, string] {
|
|
68
|
+
const index = str.indexOf(delimiter);
|
|
69
|
+
if (index === -1) return [str, ""];
|
|
70
|
+
return [str.slice(0, index), str.slice(index)];
|
|
71
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,8 @@ export * from "./AbstractElems.ts";
|
|
|
2
2
|
export * from "./BindIdents.ts";
|
|
3
3
|
export * from "./debug/ASTtoString.ts";
|
|
4
4
|
export * from "./debug/ScopeToString.ts";
|
|
5
|
+
export * from "./discovery/FindUnboundIdents.ts";
|
|
6
|
+
export * from "./discovery/PackageNameUtils.ts";
|
|
5
7
|
export * from "./LinkedWesl.ts";
|
|
6
8
|
export * from "./Linker.ts";
|
|
7
9
|
export * from "./LiveDeclarations.ts";
|
|
@@ -3,7 +3,7 @@ import { testLink } from "./TestLink.ts";
|
|
|
3
3
|
|
|
4
4
|
// LATER move these to cond cases? (or drop if duplicative)
|
|
5
5
|
|
|
6
|
-
test("conditional
|
|
6
|
+
test("conditional declaration ", async () => {
|
|
7
7
|
const app = `
|
|
8
8
|
fn main() {
|
|
9
9
|
@if(false) let x = 1;
|
|
@@ -17,6 +17,22 @@ test("conditional statement", async () => {
|
|
|
17
17
|
await testLink({ app: app }, "app", expectWgsl);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
+
test("conditional assignment", async () => {
|
|
21
|
+
const app = `
|
|
22
|
+
fn main() {
|
|
23
|
+
var x = 1;
|
|
24
|
+
@if(false) x = 2;
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const expectWgsl = `
|
|
29
|
+
fn main() {
|
|
30
|
+
var x = 1;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
await testLink({ app: app }, "app", expectWgsl);
|
|
34
|
+
});
|
|
35
|
+
|
|
20
36
|
test("conditional compound statement", async () => {
|
|
21
37
|
const app = `
|
|
22
38
|
fn main() {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { sanitizePackageName } from "../discovery/PackageNameUtils.ts";
|
|
3
|
+
|
|
4
|
+
test("my_package", () => {
|
|
5
|
+
expect(sanitizePackageName("my_package")).toBe("my_package");
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test("my-package", () => {
|
|
9
|
+
expect(sanitizePackageName("my-package")).toBe("my_package");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("my-cool-package", () => {
|
|
13
|
+
expect(sanitizePackageName("my-cool-package")).toBe("my_cool_package");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("@scope/package", () => {
|
|
17
|
+
expect(sanitizePackageName("@scope/package")).toBe("scope__package");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("@scope/my-package", () => {
|
|
21
|
+
expect(sanitizePackageName("@scope/my-package")).toBe("scope__my_package");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("@scope/my_package", () => {
|
|
25
|
+
expect(sanitizePackageName("@scope/my_package")).toBe("scope__my_package");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("@my-org/my-cool-package", () => {
|
|
29
|
+
expect(sanitizePackageName("@my-org/my-cool-package")).toBe(
|
|
30
|
+
"my_org__my_cool_package",
|
|
31
|
+
);
|
|
32
|
+
});
|