POS API smartGrid → action Codemod#23
Open
ShadiBitaraf wants to merge 12 commits intomainfrom
Open
Conversation
- Set up basic codemod structure with workflow and package configuration - Add TypeScript configuration for development - Implement AST-based smartGrid to action transformation - Add basic test fixtures for validation
- Add getImports() with support for all import patterns - Add getNamedImports() for specific import extraction - Add getVariableAliases() for dynamic alias detection - Add isValidObjectReference() with edge case handling - Provide foundation for reusable codemod utilities
- Extract utility functions (getApiAliases, isValidObjectReference) - Add shouldTransformProperty() helper for cleaner code - Support complex patterns: this?.api?, getApi()?, function calls - Improve alias detection with proper destructuring support - Add comprehensive documentation and comments
- Add shopify-pos-extension.ts with realistic POS patterns - Add legacy-patterns.ts with class-based and complex patterns - Add pos-checkout-extension.js with JavaScript patterns - Add README documentation for testing
mohebifar
reviewed
Sep 18, 2025
Comment on lines
+2
to
+10
| export interface SgNode { | ||
| text(): string; | ||
| kind(): string; | ||
| parent(): SgNode | null; | ||
| field(name: string): SgNode | null; | ||
| getMatch(name: string): SgNode | null; | ||
| replace(text: string): any; | ||
| findAll(config: { rule: any }): SgNode[]; | ||
| } |
Member
There was a problem hiding this comment.
You can import SgNode from @codemod.com/jssg-types/main
| export interface ImportInfo { | ||
| source: string; | ||
| specifier: string; | ||
| node: any; |
Member
There was a problem hiding this comment.
You should refrain from using any types. This should probably be a SgNode<TS, "import_statement">?
Comment on lines
+32
to
+63
| export function getVariableAliases( | ||
| rootNode: any, | ||
| sourceVar: string, | ||
| destructuredProps: string[] = [] | ||
| ): Set<string> { | ||
| const aliases = new Set<string>([sourceVar]); | ||
|
|
||
| // Pattern 1: const myVar = sourceVar | ||
| const directAliases = rootNode.findAll({ | ||
| rule: { pattern: `const $VAR = ${sourceVar}` }, | ||
| }); | ||
|
|
||
| for (const alias of directAliases) { | ||
| const varName = alias.getMatch("VAR")?.text(); | ||
| if (varName) { | ||
| aliases.add(varName); | ||
| } | ||
| } | ||
|
|
||
| // Pattern 2: const { prop } = sourceVar (for specified destructured properties) | ||
| for (const prop of destructuredProps) { | ||
| const destructuring = rootNode.findAll({ | ||
| rule: { pattern: `const { ${prop} } = ${sourceVar}` }, | ||
| }); | ||
|
|
||
| if (destructuring.length > 0) { | ||
| aliases.add(prop); | ||
| } | ||
| } | ||
|
|
||
| return aliases; | ||
| } |
Member
There was a problem hiding this comment.
This is not taking into account var and let kinds i think
| property: string, | ||
| method?: string | ||
| ): any[] { | ||
| const usages: any[] = []; |
Comment on lines
+95
to
+137
| const methodPattern = method ? `.${method}($$$ARGS)` : ""; | ||
|
|
||
| for (const alias of objectAliases) { | ||
| if (alias === property) { | ||
| // Special case: direct property usage (from destructuring) | ||
| const directUsages = rootNode.findAll({ | ||
| rule: { pattern: `${alias}${methodPattern}` }, | ||
| }); | ||
| usages.push(...directUsages); | ||
| } else { | ||
| // Normal case: alias.property.method() | ||
| const memberUsages = rootNode.findAll({ | ||
| rule: { pattern: `${alias}.${property}${methodPattern}` }, | ||
| }); | ||
| usages.push(...memberUsages); | ||
| } | ||
| } | ||
|
|
||
| // Handle this.alias patterns | ||
| const thisUsages = rootNode.findAll({ | ||
| rule: { | ||
| pattern: `this.${ | ||
| Array.from(objectAliases)[0] | ||
| }.${property}${methodPattern}`, | ||
| }, | ||
| }); | ||
| usages.push(...thisUsages); | ||
|
|
||
| // Handle optional chaining | ||
| const optionalUsages = rootNode.findAll({ | ||
| rule: { | ||
| pattern: `${Array.from(objectAliases)[0]}?.${property}${methodPattern}`, | ||
| }, | ||
| }); | ||
| usages.push(...optionalUsages); | ||
|
|
||
| // Handle function call patterns | ||
| const functionCallUsages = rootNode.findAll({ | ||
| rule: { pattern: `$FUNC().${property}${methodPattern}` }, | ||
| }); | ||
| usages.push(...functionCallUsages); | ||
|
|
||
| return usages; |
Member
There was a problem hiding this comment.
This is a good util function to have, but I'd just traverse the member expression like a linked list instead of using string ops. The current code is not readable and hard to follow (and honestly I can't really trust if it covers all the edge cases as it's heavily relying on ast-grep pattern matchers)
| * // Find all Polaris imports | ||
| * const polarisImports = getImports(rootNode, "@shopify/polaris"); | ||
| */ | ||
| export function getImports(rootNode: any, packageName: string): ImportInfo[] { |
| packageName: string, | ||
| importName: string | ||
| ): any[] { | ||
| const nodes: any[] = []; |
| * const buttonImports = getNamedImports(rootNode, "@shopify/polaris", "Button"); | ||
| */ | ||
| export function getNamedImports( | ||
| rootNode: any, |
| * @deprecated Use getImports(rootNode, packageName) instead | ||
| */ | ||
| export function getImportSources( | ||
| rootNode: any, |
- Add getMemberExpressionChain() for robust member expression parsing - Add matchesMemberPattern() for clean pattern validation - Replace findMemberExpressions() with proper AST traversal approach
…ation - Add generic hasImportsMatching() function with flexible pattern matching (includes/startsWith/exact) - Add isPOSUIExtensionsFile() for comprehensive POS UI Extensions detection (old and new packages) - Remove duplicate utility functions from pos-api-smartgrid codemod - Import reusable functions from utils/ast-utils.ts instead of local duplicates
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds a codemod to migrate Shopify POS extensions from the deprecated
api.smartGrid.presentModal()→api.action.presentModal().Key Features
presentModalcalls, preserving other smartGrid methodsutils/ast-utils.ts)Impact
Files Added
utils/ast-utils.tscodemods/pos-api-smartgrid-to-action/(implementation, tests, docs)