Comparing version 6.10.0 to 6.11.0
@@ -27,2 +27,7 @@ import { Node } from "./Node"; | ||
}; | ||
/** | ||
* The file path (relative or absolute) to the utilities module from which all `ConditionalOutput` imports will be sourced. | ||
* If specified, all `ConditionalOutput` instances will be replaced with imports from this file instead of their original locations. | ||
*/ | ||
conditionalUtils?: string; | ||
} | ||
@@ -47,2 +52,6 @@ export declare class Code extends Node { | ||
toCodeString(used: ConditionalOutput[]): string; | ||
/** | ||
* Recursively collects all `ConditionalOutput` instances used within this `Code` block. | ||
*/ | ||
collectConditionalOutputs(): ConditionalOutput[]; | ||
private deepFindAll; | ||
@@ -49,0 +58,0 @@ private deepReplaceNamedImports; |
@@ -44,3 +44,18 @@ "use strict"; | ||
} | ||
deepFindAll() { | ||
/** | ||
* Recursively collects all `ConditionalOutput` instances used within this `Code` block. | ||
*/ | ||
collectConditionalOutputs() { | ||
return this.placeholders | ||
.map((placeholder) => { | ||
if (placeholder instanceof ConditionalOutput_1.ConditionalOutput) | ||
return placeholder; | ||
if (placeholder instanceof Code) | ||
return placeholder.collectConditionalOutputs(); | ||
return null; | ||
}) | ||
.flat() | ||
.filter((val) => !!val); | ||
} | ||
deepFindAll(utilsUrl) { | ||
const used = []; | ||
@@ -53,2 +68,6 @@ const imports = []; | ||
const placeholder = todo[i++]; | ||
if (utilsUrl && placeholder instanceof ConditionalOutput_1.ConditionalOutput) { | ||
imports.push(Import_1.Import.importsName(placeholder.usageSiteName, utilsUrl, placeholder.isType)); | ||
continue; | ||
} | ||
if (placeholder instanceof Node_1.Node) { | ||
@@ -140,3 +159,3 @@ todo.push(...placeholder.childNodes); | ||
} | ||
const [used, imports, defs] = this.deepFindAll(); | ||
const [used, imports, defs] = this.deepFindAll(opts.conditionalUtils); | ||
assignAliasesIfNeeded(defs, imports, ourModulePath); | ||
@@ -143,0 +162,0 @@ const importPart = (0, Import_1.emitImports)(imports, ourModulePath, importMappings, forceRequireImport, importExtensions); |
@@ -15,2 +15,7 @@ import { Node } from "./Node"; | ||
* | ||
* Additionally, if the `conditionalUtils` option is provided when calling | ||
* `toString()`, all `ConditionalOutput` instances will be imported from the specified file. | ||
* | ||
* The `isType` flag (optional) determines whether the helper should be imported as a TypeScript type when using `conditionalUtils`. | ||
* | ||
* ```typescript | ||
@@ -37,3 +42,4 @@ * const someHelper = conditionalOutput( | ||
declarationSiteCode: Code; | ||
constructor(usageSiteName: string, declarationSiteCode: Code); | ||
isType: boolean; | ||
constructor(usageSiteName: string, declarationSiteCode: Code, isType?: boolean); | ||
/** Returns the declaration code, typically to be included near the bottom of your output as top-level scope. */ | ||
@@ -40,0 +46,0 @@ get ifUsed(): MaybeOutput; |
@@ -17,2 +17,7 @@ "use strict"; | ||
* | ||
* Additionally, if the `conditionalUtils` option is provided when calling | ||
* `toString()`, all `ConditionalOutput` instances will be imported from the specified file. | ||
* | ||
* The `isType` flag (optional) determines whether the helper should be imported as a TypeScript type when using `conditionalUtils`. | ||
* | ||
* ```typescript | ||
@@ -40,6 +45,7 @@ * const someHelper = conditionalOutput( | ||
// "should I be output or not", b/c it depends on the containing tree. | ||
constructor(usageSiteName, declarationSiteCode) { | ||
constructor(usageSiteName, declarationSiteCode, isType = false) { | ||
super(); | ||
this.usageSiteName = usageSiteName; | ||
this.declarationSiteCode = declarationSiteCode; | ||
this.isType = isType; | ||
} | ||
@@ -46,0 +52,0 @@ /** Returns the declaration code, typically to be included near the bottom of your output as top-level scope. */ |
@@ -23,2 +23,4 @@ import { Import } from "./Import"; | ||
/** Creates a conditionally-output code snippet. */ | ||
export declare function conditionalOutput(usageSite: string, declarationSite: Code): ConditionalOutput; | ||
export declare function conditionalOutput(usageSite: string, declarationSite: Code, isType?: boolean): ConditionalOutput; | ||
/** Generates a `Code` block containing the provided `ConditionalOutput` declarations along with all their dependencies. */ | ||
export declare function generateConditionalsUtils(used: ConditionalOutput[]): Code; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.conditionalOutput = exports.def = exports.imp = exports.joinCode = exports.arrayOf = exports.literalOf = exports.code = exports.saveFiles = exports.Import = exports.Code = void 0; | ||
exports.generateConditionalsUtils = exports.conditionalOutput = exports.def = exports.imp = exports.joinCode = exports.arrayOf = exports.literalOf = exports.code = exports.saveFiles = exports.Import = exports.Code = void 0; | ||
const Import_1 = require("./Import"); | ||
@@ -63,5 +63,18 @@ const Code_1 = require("./Code"); | ||
/** Creates a conditionally-output code snippet. */ | ||
function conditionalOutput(usageSite, declarationSite) { | ||
return new ConditionalOutput_1.ConditionalOutput(usageSite, declarationSite); | ||
function conditionalOutput(usageSite, declarationSite, isType) { | ||
return new ConditionalOutput_1.ConditionalOutput(usageSite, declarationSite, isType); | ||
} | ||
exports.conditionalOutput = conditionalOutput; | ||
/** Generates a `Code` block containing the provided `ConditionalOutput` declarations along with all their dependencies. */ | ||
function generateConditionalsUtils(used) { | ||
const mainChunk = joinCode([ | ||
...used.map(({ declarationSiteCode }) => declarationSiteCode) | ||
], { on: '\n', trim: false }); | ||
const uniqueOutputs = [...new Set(mainChunk.collectConditionalOutputs())] | ||
.filter(output => !used.includes(output)); | ||
return joinCode([ | ||
...uniqueOutputs.map(output => code `${output.ifUsed}`), | ||
mainChunk, | ||
], { on: '\n' }); | ||
} | ||
exports.generateConditionalsUtils = generateConditionalsUtils; |
@@ -5,3 +5,3 @@ module.exports = { | ||
testEnvironment: "node", | ||
testMatch: ["<rootDir>/src/**/*-tests.+(ts|tsx|js)"], | ||
testMatch: ["<rootDir>/src/**/*.tests.+(ts|tsx|js)"], | ||
transform: { | ||
@@ -8,0 +8,0 @@ "^.+\\.(ts|tsx)$": "ts-jest", |
{ | ||
"name": "ts-poet", | ||
"version": "6.10.0", | ||
"version": "6.11.0", | ||
"description": "code generation DSL for TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
@@ -186,2 +186,44 @@ ![npm](https://img.shields.io/npm/v/ts-poet) | ||
## utils file | ||
Sometimes the generated utilities are repeated in different files, and it makes sense to put them in a separate file. | ||
To do this, you can specify that all helpers are imported from a separate module: | ||
```ts | ||
const convertTimestamps = conditionalOutput( | ||
"convertTimestamps", | ||
code`function convertTimestamps(value: any) { ...impl... }`, | ||
); | ||
const output = code` | ||
const timestamp = ${convertTimestamps}(...) | ||
`; | ||
const stringResult = output.toString({ | ||
conditionalUtils: './utils.ts' | ||
}) | ||
``` | ||
As a result, the code will be generated as if the helper had been imported. | ||
Generating the content itself for the `utils.ts` file will look something like this: | ||
```ts | ||
import { generateConditionalsUtils, code } from 'ts-poet' | ||
// get a list of all the helpers used in the code | ||
const utils = output.collectConditionalOutputs() | ||
// Create code that includes all helpers and their dependencies | ||
const utilsCode = generateConditionalsUtils(utils) | ||
const utilsCodeWithExport = code` | ||
${utilsCode} | ||
export { | ||
${utils.map(({ usageSiteName }) => usageSiteName).join(', ')} | ||
} | ||
` | ||
``` | ||
# Literals | ||
@@ -188,0 +230,0 @@ |
119145
36
2371
293
2