Skip to content

Instantly share code, notes, and snippets.

@zthxxx
Last active July 7, 2024 13:28
Show Gist options
  • Save zthxxx/075d5ca0ffa725c0feb98049619ad663 to your computer and use it in GitHub Desktop.
Save zthxxx/075d5ca0ffa725c0feb98049619ad663 to your computer and use it in GitHub Desktop.

Rewrite "import then re-export" to a direct "re-export" approach via ast-grep.

Rule file see in file-import-to-export.yml

Preview Effect

- import Form, {
+ export {
+   default as Form,
    type FormLayout,
    FormNode as Node,
  } from 'src/components/Form';
- export {
-   Form,
-   FormLayout,
-   Node,
- }

- import Tooltip from 'src/components/Button';
+ export { default as Tooltip } from 'src/components/Button';
- export { Tooltip }

- import { Button, type ButtonOption } from 'src/components/Button';
+ export { Button, type ButtonOption } from 'src/components/Button';
- export { Button, type ButtonOption }
  
- import type { CascaderOptionType } from 'src/components/Cascader';
+ export type { CascaderOptionType } from 'src/components/Cascader';
- export { CascaderOptionType }

Assumptions

  • All import are ONLY used to re-export
    • implies that all identifier in import statements are NOT used in the code, except for in re-export
  • NO renaming in re-export, ONLY have renaming in import statements
    • due to the ast-grep cannot calculate renaming back in import
  • NO export default statement

References

# [Rule File](https://ast-grep.github.io/guide/rule-config.html#rule-file)
id: import-to-export
message: rewrite import and re-export to pure re-export
severity: info # error, warning, info, hint
language: TypeScript
# use:
# ast-grep scan --color=always --update-all --filter=import-to-export
# git diff
note: |
1. remore all `export {}`
2. replace `import {}` to `export {}`, `import * as XXX` to `export * as XXX`
3. replace `import Default` to `export { default as Default }`
4. replace `import Default, { ... }` to `export { default as Default, ... }`
# step.1, remore all `export {}`
rule:
kind: export_statement
has:
kind: export_clause
not:
has:
kind: string
fix: ''
---
# step.2, replace `import {}` to `export {}`, `import * as XXX` to `export * as XXX`
rule:
pattern: import
precedes:
kind: import_clause
has:
any:
- kind: named_imports
- kind: namespace_import
not:
has:
# default import
kind: identifier
stopBy: end
fix: export
---
# step.3, replace `import Default` to `export { default as Default }`
utils:
IMPORT_STATEMENT:
kind: import_statement
any:
- pattern: import $$$IMPORT_TYPE $IMPORT_DEFAULT from '$$$'
- pattern: import $$$IMPORT_TYPE $IMPORT_DEFAULT from "$$$"
has:
matches: FROM_FRAGMENT
stopBy: end
FROM_FRAGMENT:
kind: string_fragment
pattern: $FROM_FRAGMENT
inside:
kind: import_statement
stopBy: end
rule:
matches: IMPORT_STATEMENT
has:
kind: import_clause
pattern: $IMPORT_DEFAULT
not:
has:
any:
- kind: named_imports
- kind: namespace_import
transform:
TYPED:
replace:
source: $$$IMPORT_TYPE
replace: '^.+$'
by: ' type'
fix: export {$TYPED default as $IMPORT_DEFAULT } from '$FROM_FRAGMENT';
---
# step.4, replace `import Default, { ... }` to `export { default as Default, ... }`
utils:
IMPORT_STATEMENT:
kind: import_statement
any:
- pattern: import $$$IMPORT_TYPE $IMPORT_CLAUSS from '$$$'
- pattern: import $$$IMPORT_TYPE $IMPORT_CLAUSS from "$$$"
has:
matches: FROM_FRAGMENT
stopBy: end
FROM_FRAGMENT:
kind: string_fragment
pattern: $FROM_FRAGMENT
inside:
kind: import_statement
stopBy: end
IMPORT_DEFAULT:
kind: identifier
pattern: $IMPORT_DEFAULT
inside:
kind: import_clause
NAMED_IMPORTS:
kind: named_imports
pattern: $NAMED_IMPORTS
inside:
kind: import_clause
rule:
matches: IMPORT_STATEMENT
has:
kind: import_clause
has:
matches: IMPORT_DEFAULT
precedes:
matches: NAMED_IMPORTS
stopBy: end
transform:
TYPED:
replace:
source: $$$IMPORT_TYPE
replace: '^.+$'
by: 'type '
NAMED_EXPORT:
# '{ xxx, xxx }' => ' xxx, xxx '
# '{\n xxx,\n xxx,\n}' => '\n xxx,\n xxx,\n'
substring:
source: $NAMED_IMPORTS
startChar: 1
endChar: -1
SPACING:
# '{ xxx, xxx }' => ' '
# '{\n xxx,\n xxx,\n}' => '\n '
replace:
source: $NAMED_IMPORTS
replace: ^\{(?P<spacing>\s+)\w(.|\n)*$
by: '$spacing'
fix: export {$SPACING$TYPEDdefault as $IMPORT_DEFAULT,$NAMED_EXPORT} from '$FROM_FRAGMENT';
// ------------- Bare import, Do nothing -------------
import './index.less'
// ------------- import and re-export, replace import as the follow export -------------
import Form from 'src/components/Form';
export { default as Form } from 'src/components/Form';
import type Form from 'src/components/Form';
export { type default as Form } from 'src/components/Form';
import Form from "src/components/Form";
export { default as Form } from 'src/components/Form';
import type Form from "src/components/Form";
export { type default as Form } from 'src/components/Form';
import Form, { FormLayout, FormNode as Node } from 'src/components/Form';
export { default as Form, FormLayout, FormNode as Node } from 'src/components/Form';
import Form, { type FormLayout, FormNode as Node } from 'src/components/Form';
export { default as Form, type FormLayout, FormNode as Node } from 'src/components/Form';
import { Form, FormLayout, FormNode as Node } from 'src/components/Form';
export { Form, FormLayout, FormNode as Node } from 'src/components/Form';
import { Form, type FormLayout, type FormNode as Node } from 'src/components/Form';
export { Form, type FormLayout, type FormNode as Node } from 'src/components/Form';
import type { Form, FormLayout, FormNode as Node } from 'src/components/Form';
export type { Form, FormLayout, FormNode as Node } from 'src/components/Form';
import * as Form from 'src/components/RendererEditor/globalEditors';
export * as Form from 'src/components/RendererEditor/globalEditors';
import type * as Form from 'src/components/RendererEditor/globalEditors';
export type * as Form from 'src/components/RendererEditor/globalEditors';
import Form, {
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
export {
default as Form,
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
import type Form, {
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
export {
type default as Form,
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
import {
Form,
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
export {
Form,
type FormLayout,
FormNode as Node,
} from 'src/components/Form';
import type {
Form,
FormLayout,
FormNode as Node,
} from 'src/components/Form';
export {
Form,
FormLayout,
FormNode as Node,
} from 'src/components/Form';
// ------------- Bare re-export, Remove -------------
// `export as RENAMED` is rename while export, but not rename in import,
// just remove it will cause issue
export { Form, FormLayout, FormNode as Node }
export { type Form, FormLayout, type FormNode as Node }
export type { Form, FormLayout, FormNode as Node }
// ------------- Do nothing -------------
export const cs = 'adg'
export const cs = {}
export function ast() {}
export class Ast {
cs = ''
}
export type asg = string
export default cs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment