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
59 changes: 57 additions & 2 deletions packages/eslint-plugin/src/rules/noUnsupportedSyntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,30 @@ export const noUnsupportedSyntax = createRule({
});
}

function validateFunctionParameters(
node:
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionExpression
| TSESTree.FunctionDeclaration,
) {
if (directives.getEnclosingTypegpuFunction() !== node) {
return;
}

for (const parameter of node.params) {
if (
parameter.type !== 'Identifier' &&
parameter.type !== 'AssignmentPattern' &&
(parameter.type !== 'ObjectPattern' || !isSupportedObjectBindingPattern(parameter))
) {
report(parameter, 'unsupported function parameter binding pattern');
}
}
}

return {
ArrowFunctionExpression(node) {
validateFunctionParameters(node);
if (directives.getDirectiveStack().at(-2)?.directives.includes('use gpu')) {
report(node, 'arrow function');
}
Expand All @@ -40,6 +62,12 @@ export const noUnsupportedSyntax = createRule({
if (!directives.getEnclosingTypegpuFunction()) {
return;
}

if (node.left.type === 'ObjectPattern' || node.left.type === 'ArrayPattern') {
report(node.left, 'destructuring assignment');
return;
}

if (unsupportedAssignmentOps.includes(node.operator)) {
report(node, `assignment expression '${node.operator}'`);
}
Expand Down Expand Up @@ -104,12 +132,14 @@ export const noUnsupportedSyntax = createRule({
},

FunctionDeclaration(node) {
validateFunctionParameters(node);
if (directives.getDirectiveStack().at(-2)?.directives.includes('use gpu')) {
report(node, 'function declaration');
}
},

FunctionExpression(node) {
validateFunctionParameters(node);
if (directives.getDirectiveStack().at(-2)?.directives.includes('use gpu')) {
report(node, 'function expression');
}
Expand Down Expand Up @@ -225,8 +255,23 @@ export const noUnsupportedSyntax = createRule({
if (!directives.getEnclosingTypegpuFunction()) {
return;
}
if (node.id.type !== 'Identifier') {
report(node, 'variable declaration using destructuring');

const declarationParent = node.parent?.parent;
if (
node.id.type === 'ObjectPattern' &&
(declarationParent?.type === 'ForStatement' ||
declarationParent?.type === 'ForOfStatement')
) {
report(node.id, 'object destructuring in loop header');
return;
}

if (node.id.type === 'Identifier') {
return;
}

if (node.id.type !== 'ObjectPattern' || !isSupportedObjectBindingPattern(node.id)) {
report(node, 'unsupported variable binding pattern');
}
},

Expand All @@ -243,3 +288,13 @@ export const noUnsupportedSyntax = createRule({
const unsupportedAssignmentOps = ['&&=', '**=', '||=', '??='];
const unsupportedBinaryOps = ['==', '!=', 'in', 'instanceof', '|>'];
const unsupportedUnaryOps = ['+', 'typeof', 'void', 'delete'];

function isSupportedObjectBindingPattern(pattern: TSESTree.ObjectPattern): boolean {
return pattern.properties.every(
(prop) =>
prop.type === 'Property' &&
!prop.computed &&
prop.key.type === 'Identifier' &&
prop.value.type === 'Identifier',
);
}
133 changes: 130 additions & 3 deletions packages/eslint-plugin/tests/rules/noUnsupportedSyntax.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ describe('noUnsupportedSyntax', () => {
"const fn = () => { 'use gpu'; const x = Struct({ prop: 1}); }",
"const fn = () => { 'use gpu'; let x = 1; }",
"const cls = new (class { #priv = 1; fn = () => { 'use gpu'; const a = this.#priv; } } )()",
"const fn = () => { 'use gpu'; const { a } = obj; }",
"const fn = () => { 'use gpu'; const { a, b: renamed } = obj; }",
],
invalid: [
{
Expand Down Expand Up @@ -306,11 +308,136 @@ describe('noUnsupportedSyntax', () => {
],
},
{
code: "const fn = () => { 'use gpu'; const { a } = obj; }",
code: "const fn = () => { 'use gpu'; const { nested: { a } } = obj; }",
errors: [
{
messageId: 'unexpected',
data: { snippet: '{ a } = obj', syntax: 'variable declaration using destructuring' },
data: {
snippet: '{ nested: { a } } = obj',
syntax: 'unsupported variable binding pattern',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; const { a = 1 } = obj; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ a = 1 } = obj',
syntax: 'unsupported variable binding pattern',
},
},
{
messageId: 'unexpected',
data: {
snippet: 'a = 1',
syntax: 'assignment pattern (default parameter)',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; const { ...rest } = obj; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ ...rest } = obj',
syntax: 'unsupported variable binding pattern',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; const { [key]: a } = obj; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ [key]: a } = obj',
syntax: 'unsupported variable binding pattern',
},
},
{
messageId: 'unexpected',
data: {
snippet: '[key]: a',
syntax: 'computed property key',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; for (const { value } = source; value < 10;) {} }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ value }',
syntax: 'object destructuring in loop header',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; for (const { value } of source) {} }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ value }',
syntax: 'object destructuring in loop header',
},
},
],
},
{
code: "const fn = ([a]) => { 'use gpu'; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '[a]',
syntax: 'unsupported function parameter binding pattern',
},
},
],
},
{
code: "function fn({ nested: { a } }) { 'use gpu'; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ nested: { a } }',
syntax: 'unsupported function parameter binding pattern',
},
},
],
},
{
code: "const fn = () => { 'use gpu'; let a = 0; ({ a } = obj); }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '{ a }',
syntax: 'destructuring assignment',
},
},
],
},
{
code: "const fn = function(...args) { 'use gpu'; }",
errors: [
{
messageId: 'unexpected',
data: {
snippet: '...args',
syntax: 'unsupported function parameter binding pattern',
},
},
],
},
Expand All @@ -319,7 +446,7 @@ describe('noUnsupportedSyntax', () => {
errors: [
{
messageId: 'unexpected',
data: { snippet: '[a] = arr', syntax: 'variable declaration using destructuring' },
data: { snippet: '[a] = arr', syntax: 'unsupported variable binding pattern' },
},
],
},
Expand Down
Loading
Loading