Skip to content

Commit dde8248

Browse files
committed
chore: modify some typescript script generation
1 parent ed81426 commit dde8248

2 files changed

Lines changed: 140 additions & 3 deletions

File tree

‎nx.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"sharedGlobals": [
1212
"{workspaceRoot}/.nvmrc",
1313
"{workspaceRoot}/package.json",
14+
"{workspaceRoot}/scripts/rewrite-table-core-dts.mjs",
1415
"{workspaceRoot}/tsconfig.json"
1516
],
1617
"default": [

‎scripts/rewrite-table-core-dts.mjs‎

Lines changed: 139 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
2-
import { join } from 'node:path'
2+
import { dirname, join, relative } from 'node:path'
33
import { fileURLToPath } from 'node:url'
44

55
const packageRoot = fileURLToPath(
@@ -141,29 +141,165 @@ function removeNamedSpecifiers(source, names) {
141141
)
142142
}
143143

144-
function rewriteDeclaration(source) {
144+
function rewriteInternalImportSpecifiers(source) {
145+
const replacements = new Map([
146+
['Table_Internal', 'Table'],
147+
['Column_Internal', 'Column'],
148+
])
149+
150+
return source.replace(
151+
/\bimport(\s+type)?\s+\{([^}]+)\}\s+from\s+([^;\n]+);/g,
152+
(statement, typeKeyword = '', specifiers, fromClause) => {
153+
const seen = new Set()
154+
const nextSpecifiers = []
155+
156+
for (const rawSpecifier of specifiers.split(',')) {
157+
const specifier = rawSpecifier.trim()
158+
159+
if (!specifier) {
160+
continue
161+
}
162+
163+
const isTypeSpecifier = specifier.startsWith('type ')
164+
const specifierName = getSpecifierName(specifier)
165+
const replacement = replacements.get(specifierName)
166+
const nextSpecifier = replacement
167+
? `${isTypeSpecifier ? 'type ' : ''}${replacement}`
168+
: specifier
169+
const nextSpecifierName = getSpecifierName(nextSpecifier)
170+
171+
if (seen.has(nextSpecifierName)) {
172+
continue
173+
}
174+
175+
seen.add(nextSpecifierName)
176+
nextSpecifiers.push(nextSpecifier)
177+
}
178+
179+
return `import${typeKeyword} { ${nextSpecifiers.join(
180+
', ',
181+
)} } from ${fromClause};`
182+
},
183+
)
184+
}
185+
186+
function getImportPath(fromFile, typeName) {
187+
const runtimeExtension = fromFile.endsWith('.d.cts') ? '.cjs' : '.js'
188+
const target = join(distDir, 'types', `${typeName}${runtimeExtension}`)
189+
let importPath = relative(dirname(fromFile), target).replaceAll('\\', '/')
190+
191+
if (!importPath.startsWith('.')) {
192+
importPath = `./${importPath}`
193+
}
194+
195+
return importPath
196+
}
197+
198+
function hasNamedImport(source, name, importPath) {
199+
const importPattern =
200+
/\bimport(?:\s+type)?\s+\{([^}]+)\}\s+from\s+["']([^"']+)["'];/g
201+
202+
for (const match of source.matchAll(importPattern)) {
203+
const specifiers = match[1] ?? ''
204+
const fromClause = match[2]
205+
206+
if (fromClause !== importPath) {
207+
continue
208+
}
209+
210+
if (
211+
specifiers
212+
.split(',')
213+
.map((specifier) => getSpecifierName(specifier.trim()))
214+
.includes(name)
215+
) {
216+
return true
217+
}
218+
}
219+
220+
return false
221+
}
222+
223+
function ensureNamedImport(source, name, importPath) {
224+
if (hasNamedImport(source, name, importPath)) {
225+
return source
226+
}
227+
228+
const importPattern = new RegExp(
229+
String.raw`\bimport(\s+type)?\s+\{([^}]+)\}\s+from\s+["']${importPath.replace(
230+
/[.*+?^${}()|[\]\\]/g,
231+
'\\$&',
232+
)}["'];`,
233+
)
234+
const match = importPattern.exec(source)
235+
236+
if (match) {
237+
const [statement, typeKeyword = '', specifiers] = match
238+
const nextStatement = `import${typeKeyword} { ${[
239+
...specifiers.split(',').map((specifier) => specifier.trim()),
240+
name,
241+
]
242+
.filter(Boolean)
243+
.join(', ')} } from "${importPath}";`
244+
245+
return (
246+
source.slice(0, match.index) +
247+
nextStatement +
248+
source.slice(match.index + statement.length)
249+
)
250+
}
251+
252+
return `import { ${name} } from "${importPath}";\n${source}`
253+
}
254+
255+
function ensurePublicTypeImports(source, file) {
256+
let next = source
257+
258+
if (
259+
!file.endsWith('/types/Table.d.ts') &&
260+
!file.endsWith('/types/Table.d.cts') &&
261+
/\bTable</.test(next)
262+
) {
263+
next = ensureNamedImport(next, 'Table', getImportPath(file, 'Table'))
264+
}
265+
266+
if (
267+
!file.endsWith('/types/Column.d.ts') &&
268+
!file.endsWith('/types/Column.d.cts') &&
269+
/\bColumn</.test(next)
270+
) {
271+
next = ensureNamedImport(next, 'Column', getImportPath(file, 'Column'))
272+
}
273+
274+
return next
275+
}
276+
277+
function rewriteDeclaration(source, file) {
145278
let next = source
146279

147280
for (const typeName of forbiddenTypeNames) {
148281
next = removeExportedInterface(next, typeName)
149282
}
150283

151284
next = removeTypeAlias(next, 'Table_InternalBroadenedKeys')
285+
next = rewriteInternalImportSpecifiers(next)
152286
next = removeNamedSpecifiers(next, forbiddenTypeNames)
153287

154288
next = next.replaceAll('Table_Internal<', 'Table<')
155289
next = next.replaceAll('Column_Internal<', 'Column<')
156290
next = next.replaceAll('Table_Internal', 'Table')
157291
next = next.replaceAll('Column_Internal', 'Column')
158292

293+
next = ensurePublicTypeImports(next, file)
294+
159295
return next
160296
}
161297

162298
const files = walkDeclarationFiles(distDir)
163299

164300
for (const file of files) {
165301
const source = readFileSync(file, 'utf8')
166-
const next = rewriteDeclaration(source)
302+
const next = rewriteDeclaration(source, file)
167303

168304
if (next !== source) {
169305
writeFileSync(file, next)

0 commit comments

Comments
 (0)