From 58842fb23f7bc9130bb8d3d66a5aa164101a012e Mon Sep 17 00:00:00 2001 From: Dan Freeman Date: Tue, 26 Jan 2021 18:55:35 +0100 Subject: [PATCH 1/3] Don't call `customizeComponentName` on curly components --- .../test/compiler/compile-options-test.ts | 23 +++++++++++++++++++ packages/@glimmer/syntax/lib/symbol-table.ts | 5 +++- packages/@glimmer/syntax/lib/utils.ts | 8 +++++++ .../@glimmer/syntax/lib/v2-a/normalize.ts | 9 +------- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts b/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts index aab0c13d78..560b36ea47 100644 --- a/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts +++ b/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts @@ -72,6 +72,29 @@ module('[glimmer-compiler] precompile', ({ test }) => { assert.equal(componentName, 'rental', 'customized component name was used'); }); + test('customizeComponentName is not invoked on curly components', function (assert) { + let wire = JSON.parse( + precompile('{{#my-component}}hello{{/my-component}}', { + customizeComponentName(input: string) { + return input.toUpperCase(); + }, + }) + ); + + let block: WireFormat.SerializedTemplateBlock = JSON.parse(wire.block); + + let [[, componentNameExpr]] = block[0] as [WireFormat.Statements.Block]; + + glimmerAssert( + Array.isArray(componentNameExpr) && + componentNameExpr[0] === SexpOpcodes.GetFreeAsComponentHead, + `component name is a free variable lookup` + ); + + let componentName = block[3][componentNameExpr[1]]; + assert.equal(componentName, 'my-component', 'original component name was used'); + }); + test('lowercased names are not resolved or customized in resolution mode', (assert) => { let wire = JSON.parse( precompile('', { diff --git a/packages/@glimmer/syntax/lib/symbol-table.ts b/packages/@glimmer/syntax/lib/symbol-table.ts index 7c5a112486..e94f0a52a6 100644 --- a/packages/@glimmer/syntax/lib/symbol-table.ts +++ b/packages/@glimmer/syntax/lib/symbol-table.ts @@ -2,6 +2,7 @@ import { Core, Dict, SexpOpcodes } from '@glimmer/interfaces'; import { dict } from '@glimmer/util'; import { ASTv2 } from '..'; +import { isUpperCase } from './utils'; export abstract class SymbolTable { static top( @@ -86,7 +87,9 @@ export class ProgramSymbolTable extends SymbolTable { } allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number { - if (resolution.resolution() === SexpOpcodes.GetFreeAsComponentHead) { + // If the name in question is an uppercase (i.e. angle-bracket) component invocation, run + // the optional `customizeComponentName` function provided to the precompiler. + if (resolution.resolution() === SexpOpcodes.GetFreeAsComponentHead && isUpperCase(name)) { name = this.customizeComponentName(name); } diff --git a/packages/@glimmer/syntax/lib/utils.ts b/packages/@glimmer/syntax/lib/utils.ts index bd717f251a..05fe8483f0 100644 --- a/packages/@glimmer/syntax/lib/utils.ts +++ b/packages/@glimmer/syntax/lib/utils.ts @@ -114,3 +114,11 @@ export function printLiteral(literal: ASTv1.Literal): string { return JSON.stringify(literal.value); } } + +export function isUpperCase(tag: string): boolean { + return tag[0] === tag[0].toUpperCase() && tag[0] !== tag[0].toLowerCase(); +} + +export function isLowerCase(tag: string): boolean { + return tag[0] === tag[0].toLowerCase() && tag[0] !== tag[0].toUpperCase(); +} diff --git a/packages/@glimmer/syntax/lib/v2-a/normalize.ts b/packages/@glimmer/syntax/lib/v2-a/normalize.ts index 2cd78a4149..fd189104df 100644 --- a/packages/@glimmer/syntax/lib/v2-a/normalize.ts +++ b/packages/@glimmer/syntax/lib/v2-a/normalize.ts @@ -10,6 +10,7 @@ import { SourceSpan } from '../source/span'; import { SpanList } from '../source/span-list'; import { BlockSymbolTable, ProgramSymbolTable, SymbolTable } from '../symbol-table'; import { generateSyntaxError } from '../syntax-error'; +import { isLowerCase, isUpperCase } from '../utils'; import * as ASTv1 from '../v1/api'; import b from '../v1/parser-builders'; import * as ASTv2 from './api'; @@ -866,14 +867,6 @@ class ElementChildren extends Children { } } -function isUpperCase(tag: string): boolean { - return tag[0] === tag[0].toUpperCase() && tag[0] !== tag[0].toLowerCase(); -} - -function isLowerCase(tag: string): boolean { - return tag[0] === tag[0].toLowerCase() && tag[0] !== tag[0].toUpperCase(); -} - function printPath(node: ASTv1.PathExpression | ASTv1.CallNode): string { if (node.type !== 'PathExpression' && node.path.type === 'PathExpression') { return printPath(node.path); From c933b412f2a2d389b514c1aaaa609faceef07546 Mon Sep 17 00:00:00 2001 From: "James C. Davis" Date: Tue, 26 Jan 2021 17:16:07 -0500 Subject: [PATCH 2/3] add test for angle-bracket-like name invoked with curlies --- .../test/compiler/compile-options-test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts b/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts index 560b36ea47..b8096882a0 100644 --- a/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts +++ b/packages/@glimmer/integration-tests/test/compiler/compile-options-test.ts @@ -95,6 +95,29 @@ module('[glimmer-compiler] precompile', ({ test }) => { assert.equal(componentName, 'my-component', 'original component name was used'); }); + test('customizeComponentName is not invoked on angle-bracket-like name invoked with curlies', function (assert) { + let wire = JSON.parse( + precompile('{{#MyComponent}}hello{{/MyComponent}}', { + customizeComponentName(input: string) { + return input.toUpperCase(); + }, + }) + ); + + let block: WireFormat.SerializedTemplateBlock = JSON.parse(wire.block); + + let [[, componentNameExpr]] = block[0] as [WireFormat.Statements.Block]; + + glimmerAssert( + Array.isArray(componentNameExpr) && + componentNameExpr[0] === SexpOpcodes.GetFreeAsComponentHead, + `component name is a free variable lookup` + ); + + let componentName = block[3][componentNameExpr[1]]; + assert.equal(componentName, 'MyComponent', 'original component name was used'); + }); + test('lowercased names are not resolved or customized in resolution mode', (assert) => { let wire = JSON.parse( precompile('', { From 5c0cf6cc2d29bc439d0113829bcbcd5406a876bb Mon Sep 17 00:00:00 2001 From: Chris Garrett Date: Fri, 29 Jan 2021 15:01:57 -0800 Subject: [PATCH 3/3] Add angle-bracket information to resolutions --- packages/@glimmer/syntax/lib/symbol-table.ts | 6 +++++- .../syntax/lib/v2-a/loose-resolution.ts | 2 +- .../syntax/lib/v2-a/objects/resolution.ts | 17 +++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/@glimmer/syntax/lib/symbol-table.ts b/packages/@glimmer/syntax/lib/symbol-table.ts index e94f0a52a6..a5fce6039f 100644 --- a/packages/@glimmer/syntax/lib/symbol-table.ts +++ b/packages/@glimmer/syntax/lib/symbol-table.ts @@ -89,7 +89,11 @@ export class ProgramSymbolTable extends SymbolTable { allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number { // If the name in question is an uppercase (i.e. angle-bracket) component invocation, run // the optional `customizeComponentName` function provided to the precompiler. - if (resolution.resolution() === SexpOpcodes.GetFreeAsComponentHead && isUpperCase(name)) { + if ( + resolution.resolution() === SexpOpcodes.GetFreeAsComponentHead && + resolution.isAngleBracket && + isUpperCase(name) + ) { name = this.customizeComponentName(name); } diff --git a/packages/@glimmer/syntax/lib/v2-a/loose-resolution.ts b/packages/@glimmer/syntax/lib/v2-a/loose-resolution.ts index c4b950a986..2de376faa1 100644 --- a/packages/@glimmer/syntax/lib/v2-a/loose-resolution.ts +++ b/packages/@glimmer/syntax/lib/v2-a/loose-resolution.ts @@ -39,7 +39,7 @@ export function BlockSyntaxContext(node: ASTv1.BlockStatement): ASTv2.FreeVarRes export function ComponentSyntaxContext(node: ASTv1.PathExpression): ASTv2.FreeVarResolution | null { if (isSimplePath(node)) { - return ASTv2.LooseModeResolution.namespaced(ASTv2.FreeVarNamespace.Component); + return ASTv2.LooseModeResolution.namespaced(ASTv2.FreeVarNamespace.Component, true); } else { return null; } diff --git a/packages/@glimmer/syntax/lib/v2-a/objects/resolution.ts b/packages/@glimmer/syntax/lib/v2-a/objects/resolution.ts index 055eef4956..9a651e4500 100644 --- a/packages/@glimmer/syntax/lib/v2-a/objects/resolution.ts +++ b/packages/@glimmer/syntax/lib/v2-a/objects/resolution.ts @@ -22,6 +22,8 @@ export class StrictResolution { serialize(): SerializedResolution { return 'Strict'; } + + readonly isAngleBracket = false; } export const STRICT_RESOLUTION = new StrictResolution(); @@ -46,11 +48,14 @@ export class LooseModeResolution { * * @see {NamespacedAmbiguity} */ - static namespaced(namespace: FreeVarNamespace): LooseModeResolution { - return new LooseModeResolution({ - namespaces: [namespace], - fallback: false, - }); + static namespaced(namespace: FreeVarNamespace, isAngleBracket = false): LooseModeResolution { + return new LooseModeResolution( + { + namespaces: [namespace], + fallback: false, + }, + isAngleBracket + ); } /** @@ -136,7 +141,7 @@ export class LooseModeResolution { return new LooseModeResolution({ namespaces: [FreeVarNamespace.Helper], fallback: true }); } - constructor(readonly ambiguity: Ambiguity) {} + constructor(readonly ambiguity: Ambiguity, readonly isAngleBracket = false) {} resolution(): GetContextualFreeOp { if (this.ambiguity.namespaces.length === 0) {