file factory (name pending) util and unindent util
Closed this issue · 4 comments
Just started using this to create virtual modules and dts files. This is just an idea, but would make it easier.
// file-factory.ts
import { unindent } from './unindent'
export const fileFactory = () => {
let file = ``
return {
addLines(lines: string) {
file += unindent`${ lines }`
},
text() {
return file
}
}
}
// unindent-ts
export function unindent(strings, ...values) {
const result = [];
const template = strings.reduce((prev, current) => prev + values.shift() + current);
// Find the common indentation
const indentMatch = template.match(/^\n?(\s*)/);
const commonIndent = indentMatch ? indentMatch[1].length : 0;
// Remove common indentation from each line
const lines = template.split('\n');
for (let line of lines) {
result.push(line.slice(commonIndent));
}
// Join the lines back together
return result.join('\n');
}
Basically means you can create virtual modules and dts files much nicer:
"astro:setup:config": () => {
const virtualModule = fileFactory()
virtualModule.addLines(`
export default ${ JSON.stringify({}) }
`)
}
outputs
export default {}
all nicely formatted n stuff so you don't have to worry about indents and messy af dts files if you're trying to dynamically generate
mmh could it be possible to take the content
and format it without a super huge dependency instead (or even none)? this way users don't have to think about it, they pass their file content badly formatted and we do it for them?
Misunderstanding: Related to this issue #65 about generating virtual module import/exports, if AIK generates import/exports it could also generate types for the module which would require a way to buffer lines/types and compile into a string for addDts
+1 for having this functionality native to addDts
or AIK in general it would make it a lot easier to generate good clean looking types (and do so dynamically)
I have a small implementation for something similar here to get an idea on how to do something like this without a package. I originally authored this as a plugin for AIK but had to move away from defineIntegration
for more control over typing. This is what my API looked while I had a plugin:
"astro:config:setup": ({ createDtsBuffer }) => {
const {
createLineBuffer,
addLinesToDts,
addLinesToDtsInterface,
addLinesToDtsNamespace,
addLinesToDtsModule,
writeDtsBuffer,
} = createDtsBuffer("my-integration")
// Add lines to .d.ts file
addLinesToDts(`
type ThemeName = "${themeName}";
type ThemeConfig = NonNullable<Parameters<typeof import("${entrypoint}").default>[0]>["config"]
`)
// Add lines for virtual module 'my-module'
addLinesToDtsModule(
"my-module",
Object.entries(objectModule)
.map(([name, entrypoint]) => `export const "${camelCase(name)}": typeof import("${resolveImport(entrypoint)}").default;`)
);
// Create your own line buffer (useful for generating nested types like objects inside interfaces)
const typeBuffer = createLineBuffer()
typeBuffer.add(Object.entries(objectModule).map(() => ...))
// Using the line buffer
addLinesToDtsInterface(
"SomeInterface",
typeBuffer.lines
)
// Compile buffer into a string and write to .d.ts file
writeDtsBuffer()
}
(This is just an example of how I solved this, not necessarily a suggestion for a full AIK API)
@florian-lefebvre Yeah I'd be up for both! There are times when you want to dynamically create dts content or virtual module content and a helper like FileFactory
or the far, far superior createLineBuffer
@BryceRussell mentioned is a handy way to do it.
That being said we can definitely run the content pass into addDts
through unindent
and then at least then the user doesn't have to worry about that for one off-files or whatever and still gets neat af files
That one sounds interesting, idk if it has support for TS https://github.com/benjamn/recast
EDIT: it has support for it by specifying a specific parser