@maratus-codemod/rewrite-internal-imports 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@maratus-codemod/rewrite-internal-imports",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
+ "files": [
6
+ "dist"
7
+ ],
5
8
  "type": "module",
6
9
  "exports": {
7
10
  ".": "./dist/index.mjs"
package/CHANGELOG.md DELETED
@@ -1,12 +0,0 @@
1
- # @maratus-codemod/rewrite-internal-imports
2
-
3
- ## 0.1.0
4
-
5
- ### Minor Changes
6
-
7
- - 479324d: Publish the initial public Maratus packages, including the CLI, platform binaries, codemod runner, codemods, runtime libraries, and the first registry components: separator, button, focus-modality.
8
-
9
- ### Patch Changes
10
-
11
- - Updated dependencies [479324d]
12
- - @maratus/codemod-runner@0.1.0
@@ -1,96 +0,0 @@
1
- import type { InternalImportTarget } from './index'
2
- import type { ImportDeclaration } from 'ts-morph'
3
-
4
- export type InternalImportDeclaration = {
5
- moduleSpecifier: string
6
- defaultImport?: string
7
- namespaceImport?: string
8
- namedImports?: string[]
9
- }
10
-
11
- export function buildInternalImportDeclarations(
12
- importDeclaration: ImportDeclaration,
13
- target: InternalImportTarget,
14
- ) {
15
- const namedImports = importDeclaration.getNamedImports()
16
- const namedImportsByPath = new Map<string, string[]>()
17
-
18
- for (const namedImport of namedImports) {
19
- const importName = namedImport.getName()
20
- const modulePath = target.namedPaths?.[importName]
21
-
22
- if (!modulePath) {
23
- continue
24
- }
25
-
26
- const existing = namedImportsByPath.get(modulePath) ?? []
27
- existing.push(namedImport.getText())
28
- namedImportsByPath.set(modulePath, existing)
29
- }
30
-
31
- const nextDeclarations: InternalImportDeclaration[] = []
32
-
33
- const defaultImport = importDeclaration.getDefaultImport()?.getText()
34
- if (defaultImport && target.defaultPath) {
35
- nextDeclarations.push({
36
- moduleSpecifier: target.defaultPath,
37
- defaultImport,
38
- })
39
- }
40
-
41
- const namespaceImport = importDeclaration.getNamespaceImport()?.getText()
42
- if (namespaceImport && target.namespacePath) {
43
- nextDeclarations.push({
44
- moduleSpecifier: target.namespacePath,
45
- namespaceImport,
46
- })
47
- }
48
-
49
- for (const [moduleSpecifier, groupedNamedImports] of namedImportsByPath) {
50
- nextDeclarations.push({
51
- moduleSpecifier,
52
- namedImports: groupedNamedImports,
53
- })
54
- }
55
-
56
- if (
57
- importDeclaration.getImportClause() === undefined &&
58
- target.sideEffectPath
59
- ) {
60
- nextDeclarations.push({
61
- moduleSpecifier: target.sideEffectPath,
62
- })
63
- }
64
-
65
- return nextDeclarations
66
- }
67
-
68
- export function renderInternalImportDeclarations(
69
- declarations: InternalImportDeclaration[],
70
- ) {
71
- return declarations
72
- .map((declaration) => {
73
- if (
74
- declaration.defaultImport &&
75
- declaration.namedImports &&
76
- declaration.namedImports.length > 0
77
- ) {
78
- return `import ${declaration.defaultImport}, { ${declaration.namedImports.join(', ')} } from '${declaration.moduleSpecifier}'`
79
- }
80
-
81
- if (declaration.namespaceImport) {
82
- return `import * as ${declaration.namespaceImport} from '${declaration.moduleSpecifier}'`
83
- }
84
-
85
- if (declaration.defaultImport) {
86
- return `import ${declaration.defaultImport} from '${declaration.moduleSpecifier}'`
87
- }
88
-
89
- if (declaration.namedImports && declaration.namedImports.length > 0) {
90
- return `import { ${declaration.namedImports.join(', ')} } from '${declaration.moduleSpecifier}'`
91
- }
92
-
93
- return `import '${declaration.moduleSpecifier}'`
94
- })
95
- .join('\n')
96
- }
package/src/index.ts DELETED
@@ -1,14 +0,0 @@
1
- export {
2
- type InternalImportTarget,
3
- type RewriteInternalImportsOptions,
4
- type RewriteInternalPackageImportsOptions,
5
- } from './options'
6
-
7
- export { rewriteInternalImports } from './rewrite-internal-imports'
8
- export { rewriteInternalPackageImports } from './rewrite-internal-package-imports'
9
-
10
- export {
11
- type ResolvedInternalImportTargets,
12
- type ResolveInternalImportTargetsOptions,
13
- resolveInternalImportTargets,
14
- } from './resolve-targets'
package/src/options.ts DELETED
@@ -1,23 +0,0 @@
1
- export type FileNameKind = 'match-export' | 'kebab-case'
2
-
3
- export type InternalImportTarget = {
4
- barrelPath?: string
5
- sideEffectPath?: string
6
- defaultPath?: string
7
- namespacePath?: string
8
- namedPaths?: Record<string, string>
9
- }
10
-
11
- export type RewriteInternalImportsOptions = {
12
- targets: Record<string, InternalImportTarget>
13
- }
14
-
15
- export type RewriteInternalPackageImportsOptions = {
16
- packages: Array<{
17
- packageName: string
18
- sourceDir: string
19
- destinationDir: string
20
- barrel: boolean
21
- fileNameKind: FileNameKind
22
- }>
23
- }
@@ -1,122 +0,0 @@
1
- import type { FileNameKind, InternalImportTarget } from './options'
2
- import { existsSync } from 'node:fs'
3
- import path from 'node:path'
4
- import { rewriteSourcePath } from '@maratus/codemod-runner'
5
- import { Project } from 'ts-morph'
6
-
7
- export type ResolveInternalImportTargetsOptions = {
8
- sourceFilePath: string
9
- packages: Array<{
10
- packageName: string
11
- sourceDir: string
12
- destinationDir: string
13
- barrel: boolean
14
- fileNameKind: FileNameKind
15
- }>
16
- }
17
-
18
- export type ResolvedInternalImportTargets = Record<string, InternalImportTarget>
19
-
20
- export function resolveInternalImportTargets(
21
- options: ResolveInternalImportTargetsOptions,
22
- ): ResolvedInternalImportTargets {
23
- const targets: ResolvedInternalImportTargets = {}
24
-
25
- for (const internalPackage of options.packages) {
26
- const packageName = `@maratus/${internalPackage.packageName}`
27
-
28
- if (internalPackage.barrel) {
29
- targets[packageName] = {
30
- barrelPath: relativeModuleSpecifier(
31
- options.sourceFilePath,
32
- internalPackage.destinationDir,
33
- ),
34
- }
35
- continue
36
- }
37
-
38
- const indexSourceFilePath = resolvePackageIndexFile(
39
- internalPackage.sourceDir,
40
- )
41
- if (!indexSourceFilePath) {
42
- continue
43
- }
44
-
45
- const project = new Project({
46
- useInMemoryFileSystem: false,
47
- })
48
- const indexSourceFile = project.addSourceFileAtPath(indexSourceFilePath)
49
- const exportedDeclarations = indexSourceFile.getExportedDeclarations()
50
- const namedPaths: Record<string, string> = {}
51
-
52
- for (const [exportName, declarations] of exportedDeclarations) {
53
- const declaration = declarations[0]
54
- if (!declaration) {
55
- continue
56
- }
57
-
58
- const declarationFile = declaration.getSourceFile().getFilePath()
59
- const relativeSourcePath = path.relative(
60
- internalPackage.sourceDir,
61
- declarationFile,
62
- )
63
- const destinationFilePath = path.join(
64
- internalPackage.destinationDir,
65
- rewriteSourcePath(relativeSourcePath, internalPackage.fileNameKind),
66
- )
67
-
68
- namedPaths[exportName] = relativeModuleSpecifier(
69
- options.sourceFilePath,
70
- destinationFilePath,
71
- )
72
- }
73
-
74
- targets[packageName] = {
75
- namedPaths,
76
- }
77
- }
78
-
79
- return targets
80
- }
81
-
82
- function resolvePackageIndexFile(sourceDir: string) {
83
- for (const candidate of ['index.ts', 'index.tsx']) {
84
- const sourceFilePath = path.join(sourceDir, candidate)
85
- if (existsSync(sourceFilePath)) {
86
- return sourceFilePath
87
- }
88
- }
89
-
90
- return null
91
- }
92
-
93
- function relativeModuleSpecifier(fromFilePath: string, toPath: string) {
94
- const normalizedToPath = path.normalize(toPath)
95
- const relativePath = path.relative(
96
- path.dirname(fromFilePath),
97
- normalizedToPath,
98
- )
99
- const withoutExt = hasSourceExtension(normalizedToPath)
100
- ? relativePath.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '')
101
- : relativePath
102
- let modulePath = withoutExt.split(path.sep).join('/')
103
-
104
- if (modulePath.endsWith('/.')) {
105
- modulePath = modulePath.slice(0, -2)
106
- }
107
- if (modulePath === '' || modulePath == '.') {
108
- return './'
109
- }
110
-
111
- if (modulePath.startsWith('.')) {
112
- return modulePath
113
- }
114
-
115
- return `./${modulePath}`
116
- }
117
-
118
- function hasSourceExtension(pathValue: string) {
119
- return ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(
120
- path.extname(pathValue),
121
- )
122
- }
@@ -1,84 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
- import { runCodemod } from '@maratus/codemod-runner'
3
- import { rewriteInternalImports } from './rewrite-internal-imports'
4
-
5
- describe(rewriteInternalImports, () => {
6
- it('rewrites to the barrel path when one is provided', async () => {
7
- const [result] = await runCodemod(
8
- rewriteInternalImports,
9
- [
10
- {
11
- path: '/consumer/components/component/component.tsx',
12
- sourceText: "import { useTestHook } from '@maratus/lib-hook'\n",
13
- },
14
- ],
15
- {
16
- targets: {
17
- '@maratus/lib-hook': {
18
- barrelPath: '../../lib/lib-hook',
19
- },
20
- },
21
- },
22
- )
23
-
24
- expect(result.sourceText).toContain(
25
- "import { useTestHook } from '../../lib/lib-hook'",
26
- )
27
- })
28
-
29
- it('splits named imports by file path when no barrel path is provided', async () => {
30
- const [result] = await runCodemod(
31
- rewriteInternalImports,
32
- [
33
- {
34
- path: '/consumer/components/component/component.tsx',
35
- sourceText:
36
- "import { useLibHook, useTestHook } from '@maratus/lib-hook'\n",
37
- },
38
- ],
39
- {
40
- targets: {
41
- '@maratus/lib-hook': {
42
- namedPaths: {
43
- useLibHook: '../../lib/lib-hook/useLibHook',
44
- useTestHook: '../../lib/lib-hook/useTestHook',
45
- },
46
- },
47
- },
48
- },
49
- )
50
-
51
- expect(result.sourceText).toContain(
52
- "import { useLibHook } from '../../lib/lib-hook/useLibHook'",
53
- )
54
- expect(result.sourceText).toContain(
55
- "import { useTestHook } from '../../lib/lib-hook/useTestHook'",
56
- )
57
- })
58
-
59
- it('groups named imports that resolve to the same file path', async () => {
60
- const [result] = await runCodemod(
61
- rewriteInternalImports,
62
- [
63
- {
64
- path: '/consumer/components/example/example.ts',
65
- sourceText: "import { A, B } from '@maratus/example-lib'\n",
66
- },
67
- ],
68
- {
69
- targets: {
70
- '@maratus/example-lib': {
71
- namedPaths: {
72
- A: '../../lib/example-lib/a',
73
- B: '../../lib/example-lib/a',
74
- },
75
- },
76
- },
77
- },
78
- )
79
-
80
- expect(result.sourceText).toContain(
81
- "import { A, B } from '../../lib/example-lib/a'",
82
- )
83
- })
84
- })
@@ -1,46 +0,0 @@
1
- import type { RewriteInternalImportsOptions } from './options'
2
- import type { Codemod } from '@maratus/codemod-runner'
3
- import {
4
- buildInternalImportDeclarations,
5
- renderInternalImportDeclarations,
6
- } from './declarations'
7
-
8
- export const rewriteInternalImports: Codemod<RewriteInternalImportsOptions> = ({
9
- files,
10
- options,
11
- project,
12
- }) => {
13
- for (const file of files) {
14
- const sourceFile = project.getSourceFile(file.path)
15
- if (!sourceFile) continue
16
-
17
- for (const importDeclaration of sourceFile.getImportDeclarations()) {
18
- const packageName = importDeclaration.getModuleSpecifierValue()
19
- const target = options.targets[packageName]
20
- if (!target) continue
21
-
22
- if (target.barrelPath) {
23
- importDeclaration.setModuleSpecifier(target.barrelPath)
24
- continue
25
- }
26
-
27
- const nextDeclarations = buildInternalImportDeclarations(
28
- importDeclaration,
29
- target,
30
- )
31
-
32
- if (nextDeclarations.length === 0) {
33
- continue
34
- }
35
-
36
- importDeclaration.replaceWithText(
37
- renderInternalImportDeclarations(nextDeclarations),
38
- )
39
- }
40
- }
41
-
42
- return files.map((file) => ({
43
- path: file.path,
44
- sourceText: project.getSourceFileOrThrow(file.path).getFullText(),
45
- }))
46
- }
@@ -1,33 +0,0 @@
1
- import { describe, expect, it } from 'bun:test'
2
- import { runCodemod } from '@maratus/codemod-runner'
3
- import { rewriteInternalPackageImports } from './rewrite-internal-package-imports'
4
-
5
- describe(rewriteInternalPackageImports, () => {
6
- it('rewrites barrel imports from a nested hook file to the lib directory path', async () => {
7
- const [result] = await runCodemod(
8
- rewriteInternalPackageImports,
9
- [
10
- {
11
- path: '/consumer/src/components/component/use-component.ts',
12
- sourceText:
13
- "import { useDependencyFeature } from '@maratus/dependency-lib'\n",
14
- },
15
- ],
16
- {
17
- packages: [
18
- {
19
- packageName: 'dependency-lib',
20
- sourceDir: '/consumer-repo/lib/dependency-lib/src',
21
- destinationDir: '/consumer/src/lib/dependency-lib',
22
- barrel: true,
23
- fileNameKind: 'kebab-case',
24
- },
25
- ],
26
- },
27
- )
28
-
29
- expect(result.sourceText).toContain(
30
- "import { useDependencyFeature } from '../../lib/dependency-lib'",
31
- )
32
- })
33
- })
@@ -1,39 +0,0 @@
1
- import type { RewriteInternalPackageImportsOptions } from './options'
2
- import type { Codemod } from '@maratus/codemod-runner'
3
- import { Project } from 'ts-morph'
4
- import { resolveInternalImportTargets } from './resolve-targets'
5
- import { rewriteInternalImports } from './rewrite-internal-imports'
6
-
7
- export const rewriteInternalPackageImports: Codemod<
8
- RewriteInternalPackageImportsOptions
9
- > = async ({ files, options }) => {
10
- const results: Array<{
11
- path: string
12
- sourceText: string
13
- }> = []
14
-
15
- for (const file of files) {
16
- const project = new Project({
17
- useInMemoryFileSystem: true,
18
- })
19
-
20
- project.createSourceFile(file.path, file.sourceText, {
21
- overwrite: true,
22
- })
23
-
24
- const rewrittenFiles = await rewriteInternalImports({
25
- files: [file],
26
- project,
27
- options: {
28
- targets: resolveInternalImportTargets({
29
- sourceFilePath: file.path,
30
- packages: options.packages,
31
- }),
32
- },
33
- })
34
-
35
- results.push(...rewrittenFiles)
36
- }
37
-
38
- return results
39
- }