-
Notifications
You must be signed in to change notification settings - Fork 0
POS API smartGrid → action Codemod #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
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
utils/ast-utils.ts
Outdated
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[]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can import SgNode from @codemod.com/jssg-types/main
utils/ast-utils.ts
Outdated
export interface ImportInfo { | ||
source: string; | ||
specifier: string; | ||
node: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should refrain from using any
types. This should probably be a SgNode<TS, "import_statement">
?
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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not taking into account var
and let
kinds i think
utils/ast-utils.ts
Outdated
property: string, | ||
method?: string | ||
): any[] { | ||
const usages: any[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no explicit any
s
utils/ast-utils.ts
Outdated
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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)
utils/ast-utils.ts
Outdated
* // Find all Polaris imports | ||
* const polarisImports = getImports(rootNode, "@shopify/polaris"); | ||
*/ | ||
export function getImports(rootNode: any, packageName: string): ImportInfo[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no explicit any
utils/ast-utils.ts
Outdated
packageName: string, | ||
importName: string | ||
): any[] { | ||
const nodes: any[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explicit any ❌
utils/ast-utils.ts
Outdated
* const buttonImports = getNamedImports(rootNode, "@shopify/polaris", "Button"); | ||
*/ | ||
export function getNamedImports( | ||
rootNode: any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any
utils/ast-utils.ts
Outdated
* @deprecated Use getImports(rootNode, packageName) instead | ||
*/ | ||
export function getImportSources( | ||
rootNode: any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
Overview
Adds a codemod to migrate Shopify POS extensions from the deprecated
api.smartGrid.presentModal()
→api.action.presentModal()
.Key Features
presentModal
calls, preserving other smartGrid methodsutils/ast-utils.ts
)Impact
Files Added
utils/ast-utils.ts
codemods/pos-api-smartgrid-to-action/
(implementation, tests, docs)