diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f110badf..ac37a27b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,6 +36,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} files: lcov.info parallel: true + fail-on-error: false coverage: needs: test @@ -45,6 +46,7 @@ jobs: uses: coverallsapp/github-action@v2 with: parallel-finished: true + fail-on-error: false automerge: diff --git a/README.md b/README.md index 5e111a07..ebcb11e6 100644 --- a/README.md +++ b/README.md @@ -282,7 +282,7 @@ src/page-name/page.js An example TypeScript page: ```typescript -import type { PageFunction } from '@domstack/static' +import type { PageFunction } from '@domstack/static/types.js' export const vars = { favoriteCookie: 'Chocolate Chip with Sea Salt' @@ -306,7 +306,7 @@ It is recommended to use some level of template processing over raw string templ ```typescript import { html } from 'htm/preact' import { dirname, basename } from 'node:path' -import type { PageFunction } from '@domstack/static' +import type { PageFunction } from '@domstack/static/types.js' type BlogVars = { favoriteCake: string @@ -518,7 +518,7 @@ The default `root.layout.ts` is featured below, and is implemented with [`preact ```typescript import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' type RootLayoutVars = { title: string, @@ -583,7 +583,7 @@ For example, you could define a `blog.layout.ts` that re-uses the `root.layout.t import defaultRootLayout from './root.layout.js' import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' // Import the type from root layout import type { RootLayoutVars } from './root.layout' @@ -813,7 +813,7 @@ A function that returns a string. The `name-of-template.txt` portion of the temp ```typescript // name-of-template.txt.template.ts -import type { TemplateFunction } from '@domstack/static' +import type { TemplateFunction } from '@domstack/static/types.js' interface TemplateVars { foo: string; @@ -839,7 +839,7 @@ export default simpleTemplate A function that returns a single object with a `content` and `outputName` entries. The `outputName` overrides the name portion of the template file name. ```typescript -import type { TemplateFunction } from '@domstack/static' +import type { TemplateFunction } from '@domstack/static/types.js' interface TemplateVars { foo: string; @@ -859,7 +859,7 @@ This is just a file with access to global vars: ${foo}`, A function that returns an array of objects with a `content` and `outputName` entries. This template file generates more than one file from a single template file. ```typescript -import type { TemplateFunction } from '@domstack/static' +import type { TemplateFunction } from '@domstack/static/types.js' interface TemplateVars { foo: string; @@ -896,7 +896,7 @@ export default objectArrayTemplate An [AsyncIterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) that `yields` objects with `content` and `outputName` entries. ```typescript -import type { TemplateAsyncIterator } from '@domstack/static' +import type { TemplateAsyncIterator } from '@domstack/static/types.js' interface TemplateVars { foo: string; @@ -951,7 +951,7 @@ The following example shows how to generate an [RSS](https://www.rssboard.org) a ```typescript import pMap from 'p-map' import jsonfeedToAtom from 'jsonfeed-to-atom' -import type { TemplateAsyncIterator } from '@domstack/static' +import type { TemplateAsyncIterator } from '@domstack/static/types.js' interface TemplateVars { title: string; @@ -1096,7 +1096,7 @@ The `global.data.js` (or `.ts`, `.mjs`, etc.) file is an optional file that can It receives a fully resolved `PageData[]` array and returns an object that is stamped onto every page's vars — making the derived data available to every page, layout, and template. ```typescript -import type { AsyncGlobalDataFunction } from '@domstack/static' +import type { AsyncGlobalDataFunction } from '@domstack/static/types.js' import { html } from 'htm/preact' import { render } from 'preact-render-to-string' @@ -1166,7 +1166,7 @@ Here is an example of using this file to polyfill node builtins in the browser b ```typescript import { polyfillNode } from 'esbuild-plugin-polyfill-node' // BuildOptions re-exported from esbuild -import type { BuildOptions } from '@domstack/static' +import type { BuildOptions } from '@domstack/static/types.js' const esbuildSettingsOverride = async (esbuildSettings: BuildOptions): Promise => { esbuildSettings.plugins = [polyfillNode()] @@ -1179,7 +1179,7 @@ export default esbuildSettingsOverride DOMStack passes its default `BuildOptions` into this function, including Preact JSX defaults and asset loader defaults for common images, icons, and fonts. You can return a shallow copy that modifies those defaults when you only need a small change. For example, this keeps DOMStack's default asset loaders and adds a custom loader for `.wasm` files: ```typescript -import type { BuildOptions } from '@domstack/static' +import type { BuildOptions } from '@domstack/static/types.js' const esbuildSettingsOverride = async (esbuildSettings: BuildOptions): Promise => { return { @@ -1197,7 +1197,7 @@ export default esbuildSettingsOverride If you want full control, reset DOMStack's convenience defaults back to esbuild's defaults while preserving the required DOMStack build wiring (`entryPoints`, `outdir`, `outbase`, etc.). From there, define only the settings you want: ```typescript -import type { BuildOptions } from '@domstack/static' +import type { BuildOptions } from '@domstack/static/types.js' const esbuildSettingsOverride = async (esbuildSettings: BuildOptions): Promise => { return { @@ -1369,7 +1369,7 @@ Install [@voxpelli/tsconfig](https://ghub.io/@voxpelli/tsconfig) which provides ### Using TypeScript with domstack Types -You can use `domstack`'s built-in types to strongly type your layout, page, and template functions. The following types are available: +You can use `domstack`'s built-in types to strongly type your layout, page, and template functions. Runtime values are imported from `@domstack/static`; types are imported from the dedicated `@domstack/static/types.js` entry. The following types are available: ```ts import type { @@ -1390,7 +1390,7 @@ import type { GlobalDataFunctionParams, PageFunctionParams, TemplateFunctionParams, -} from '@domstack/static' +} from '@domstack/static/types.js' ``` > **Note:** All function types have both synchronous and asynchronous variants (e.g., `LayoutFunction` and `AsyncLayoutFunction`). Use the async variants when your function is an `async` function. @@ -1400,7 +1400,7 @@ They are all generic and accept a variable template that you can develop and sha The data and param types (`PageData`, `PageInfo`, `TemplateInfo`, `*FunctionParams`) are useful when you want to annotate variables or helper functions that receive these objects without using the function types directly: ```ts -import type { GlobalDataFunctionParams, PageData, PageInfo } from '@domstack/static' +import type { GlobalDataFunctionParams, PageData, PageInfo } from '@domstack/static/types.js' function getPublishedPages({ pages }: GlobalDataFunctionParams): PageData[] { return pages.filter((p: PageData) => { diff --git a/docs/v12-migration.md b/docs/v12-migration.md new file mode 100644 index 00000000..428197c8 --- /dev/null +++ b/docs/v12-migration.md @@ -0,0 +1,15 @@ +# Migration Guide: domstack v12 + +This guide is a stub for breaking changes in the next major version of `@domstack/static`. + +## Type exports moved to `@domstack/static/types.js` + +In v12, runtime values remain available from `@domstack/static`, but public types have moved to a dedicated type-only entry. + +```ts +// Before v12 +import type { LayoutFunction, PageFunction, DomStackOpts } from '@domstack/static' + +// v12+ +import type { LayoutFunction, PageFunction, DomStackOpts } from '@domstack/static/types.js' +``` diff --git a/examples/basic/src/js-page/loose-assets/page.ts b/examples/basic/src/js-page/loose-assets/page.ts index 84fe842f..dbd15adf 100644 --- a/examples/basic/src/js-page/loose-assets/page.ts +++ b/examples/basic/src/js-page/loose-assets/page.ts @@ -1,5 +1,5 @@ import { html } from 'htm/preact' -import type { PageFunction } from '@domstack/static' +import type { PageFunction } from '@domstack/static/types.js' import sharedData from './shared-lib.js' import type { PageVars } from '../../layouts/root.layout.ts' diff --git a/examples/basic/src/js-page/page.js b/examples/basic/src/js-page/page.js index b9fd7360..5f063319 100644 --- a/examples/basic/src/js-page/page.js +++ b/examples/basic/src/js-page/page.js @@ -1,5 +1,5 @@ /** - * @import { PageFunction } from '@domstack/static' + * @import { PageFunction } from '@domstack/static/types.js' * @import { PageVars } from '../layouts/root.layout.js */ import { html } from 'htm/preact' diff --git a/examples/basic/src/layouts/child.layout.ts b/examples/basic/src/layouts/child.layout.ts index 6df057fe..f871723b 100644 --- a/examples/basic/src/layouts/child.layout.ts +++ b/examples/basic/src/layouts/child.layout.ts @@ -1,4 +1,4 @@ -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' import { html } from 'htm/preact' import { render } from 'preact-render-to-string' diff --git a/examples/basic/src/layouts/root.layout.ts b/examples/basic/src/layouts/root.layout.ts index 1ef49db7..1b73c44a 100644 --- a/examples/basic/src/layouts/root.layout.ts +++ b/examples/basic/src/layouts/root.layout.ts @@ -9,7 +9,7 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' export interface PageVars { title: string; diff --git a/examples/blog/src/blog/page.ts b/examples/blog/src/blog/page.ts index 83e7479e..53a5375c 100644 --- a/examples/blog/src/blog/page.ts +++ b/examples/blog/src/blog/page.ts @@ -1,6 +1,6 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { PageFunction } from '@domstack/static' +import type { PageFunction } from '@domstack/static/types.js' import type { GlobalData } from '../global.data.js' import type { SiteVars } from '../global.vars.js' diff --git a/examples/blog/src/feeds.template.ts b/examples/blog/src/feeds.template.ts index dfe42865..20697593 100644 --- a/examples/blog/src/feeds.template.ts +++ b/examples/blog/src/feeds.template.ts @@ -1,4 +1,4 @@ -import type { TemplateAsyncIterator } from '@domstack/static' +import type { TemplateAsyncIterator } from '@domstack/static/types.js' import type { SiteVars } from './global.vars.js' import type { GlobalData, BlogPost } from './global.data.js' diff --git a/examples/blog/src/global.data.ts b/examples/blog/src/global.data.ts index c0fd0b4a..64bc59dc 100644 --- a/examples/blog/src/global.data.ts +++ b/examples/blog/src/global.data.ts @@ -1,6 +1,6 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { AsyncGlobalDataFunction } from '@domstack/static' +import type { AsyncGlobalDataFunction } from '@domstack/static/types.js' export interface BlogPost { path: string diff --git a/examples/blog/src/layouts/post.layout.ts b/examples/blog/src/layouts/post.layout.ts index 88eae3a2..c3fba90f 100644 --- a/examples/blog/src/layouts/post.layout.ts +++ b/examples/blog/src/layouts/post.layout.ts @@ -1,6 +1,6 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' import rootLayout from './root.layout.ts' import type { RootVars } from './root.layout.ts' diff --git a/examples/blog/src/layouts/root.layout.ts b/examples/blog/src/layouts/root.layout.ts index 01de66d0..da2bde0a 100644 --- a/examples/blog/src/layouts/root.layout.ts +++ b/examples/blog/src/layouts/root.layout.ts @@ -1,6 +1,6 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' import type { SiteVars } from '../global.vars.js' import type { GlobalData } from '../global.data.js' diff --git a/examples/blog/src/layouts/year-index.layout.ts b/examples/blog/src/layouts/year-index.layout.ts index a4c721c0..c3442bf5 100644 --- a/examples/blog/src/layouts/year-index.layout.ts +++ b/examples/blog/src/layouts/year-index.layout.ts @@ -1,7 +1,7 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' import { dirname } from 'node:path' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' import rootLayout from './root.layout.ts' import type { RootVars } from './root.layout.ts' diff --git a/examples/css-modules/src/layouts/root.layout.js b/examples/css-modules/src/layouts/root.layout.js index f96d678f..4410e8b3 100644 --- a/examples/css-modules/src/layouts/root.layout.js +++ b/examples/css-modules/src/layouts/root.layout.js @@ -1,5 +1,5 @@ /** - * @import { LayoutFunction } from '@domstack/static' + * @import { LayoutFunction } from '@domstack/static/types.js' */ import { html } from 'htm/preact' diff --git a/examples/type-stripping/src/layouts/root.layout.ts b/examples/type-stripping/src/layouts/root.layout.ts index 33c65711..95d68fd5 100644 --- a/examples/type-stripping/src/layouts/root.layout.ts +++ b/examples/type-stripping/src/layouts/root.layout.ts @@ -1,7 +1,7 @@ import { html } from 'htm/preact' import { render } from 'preact-render-to-string' -import type { LayoutFunction } from '@domstack/static' +import type { LayoutFunction } from '@domstack/static/types.js' interface Vars { title?: string diff --git a/index.js b/index.js index bf7d47b8..33cb8cf1 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,12 @@ /** - * @import { DomStackOpts as DomStackOpts, Results, SiteData } from './lib/builder.js' + * @import { DomStackOpts, Results, SiteData } from './lib/builder.js' * @import { Stats } from 'node:fs' * @import { FSWatcher } from 'chokidar' - * @import { AsyncLayoutFunction, LayoutFunction, LayoutFunctionParams } from './lib/build-pages/page-data.js' - * @import { PageFunction, AsyncPageFunction, PageFunctionParams } from './lib/build-pages/page-builders/page-writer.js' - * @import { TemplateFunction } from './lib/build-pages/page-builders/template-builder.js' - * @import { TemplateAsyncIterator } from './lib/build-pages/page-builders/template-builder.js' - * @import { TemplateOutputOverride } from './lib/build-pages/page-builders/template-builder.js' - * @import { TemplateFunctionParams } from './lib/build-pages/page-builders/template-builder.js' - * @import { GlobalDataFunction, AsyncGlobalDataFunction, WorkerBuildStepResult, GlobalDataFunctionParams } from './lib/build-pages/index.js' - * @import { BuildOptions, BuildContext } from 'esbuild' + * @import { WorkerBuildStepResult } from './lib/build-pages/index.js' + * @import { BuildContext } from 'esbuild' * @import { PageInfo, TemplateInfo } from './lib/identify-pages.js' -*/ + * @import { TestBuildResult } from './types.js' + */ import { once } from 'events' import assert from 'node:assert' import { mkdtemp, readFile, rm } from 'node:fs/promises' @@ -53,98 +48,6 @@ import { DomStackAggregateError } from './lib/helpers/domstack-aggregate-error.j export { PageData } from './lib/build-pages/page-data.js' -/** - * @typedef {BuildOptions} BuildOptions - */ - -/** - * @template {Record} Vars - The type of variables passed to the layout function - * @template [PageReturn=any] PageReturn - The return type of the page function (defaults to any) - * @template [LayoutReturn=string] LayoutReturn - The return type of the layout function (defaults to string) - * @typedef {LayoutFunction} LayoutFunction - */ - -/** - * @template {Record} Vars - The type of variables passed to the async layout function - * @template [PageReturn=any] PageReturn - The return type of the page function (defaults to any) - * @template [LayoutReturn=string] LayoutReturn - The return type of the layout function (defaults to string) - * @typedef {AsyncLayoutFunction} AsyncLayoutFunction - */ - -/** - * @template {Record} [T=Record] - The shape of the derived vars object returned. - * @typedef {GlobalDataFunction} GlobalDataFunction - */ - -/** - * @template {Record} [T=Record] - The shape of the derived vars object returned. - * @typedef {AsyncGlobalDataFunction} AsyncGlobalDataFunction - */ - -/** - * @template {Record} Vars - The type of variables passed to the page function - * @template [PageReturn=any] PageReturn - The return type of the page function (defaults to any) - * @typedef {PageFunction} PageFunction - */ - -/** - * @template {Record} Vars - The type of variables passed to the async page function - * @template [PageReturn=any] PageReturn - The return type of the page function (defaults to any) - * @typedef {AsyncPageFunction} AsyncPageFunction - */ - -/** - * @template {Record} Vars - The type of variables for the template function - * @typedef {TemplateFunction} TemplateFunction - */ - -/** - * @template {Record} Vars - The type of variables for the template async iterator - * @typedef {TemplateAsyncIterator} TemplateAsyncIterator - */ - -/** - * @typedef {TemplateOutputOverride} TemplateOutputOverride - */ - -/** - * @typedef {PageInfo} PageInfo - */ - -/** - * @typedef {TemplateInfo} TemplateInfo - */ - -/** - * @template {Record} Vars - The type of variables passed to the layout function - * @template [PageReturn=any] PageReturn - The return type of the page function - * @template [LayoutReturn=string] LayoutReturn - The return type of the layout function - * @typedef {LayoutFunctionParams} LayoutFunctionParams - */ - -/** - * @typedef {GlobalDataFunctionParams} GlobalDataFunctionParams - */ - -/** - * @template {Record} Vars - The type of variables passed to the page function - * @template [PageReturn=any] PageReturn - The return type of the page function - * @typedef {PageFunctionParams} PageFunctionParams - */ - -/** - * @template {Record} [Vars=Record] - The type of variables for the template function - * @typedef {TemplateFunctionParams} TemplateFunctionParams - */ - -/** - * @typedef TestBuildResult - * @property {string} dest - Temporary destination directory used for the build. - * @property {Results} results - DomStack build results. - * @property {(path: string) => Promise} readOutput - Read a UTF-8 file from the temporary destination directory. - * @property {() => Promise} cleanup - Remove the temporary destination directory. - */ - const DEFAULT_IGNORES = /** @type {const} */ ([ '.*', 'coverage', diff --git a/lib/defaults/default.root.layout.js b/lib/defaults/default.root.layout.js index 9b8164c2..138886d7 100644 --- a/lib/defaults/default.root.layout.js +++ b/lib/defaults/default.root.layout.js @@ -1,5 +1,5 @@ /** - * @import { LayoutFunction } from '../../index.js' + * @import { LayoutFunction } from '#types' * @import { VNode } from 'preact' */ import { html } from 'htm/preact' diff --git a/package.json b/package.json index 1ec8bebc..80aae41e 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,13 @@ "version": "11.0.3", "type": "module", "main": "./index.js", - "types": "index.d.ts", + "types": "./index.d.ts", + "imports": { + "#types": { + "types": "./types.d.ts", + "default": "./types.ts" + } + }, "bin": { "domstack": "./bin.js", "dom": "./bin.js" diff --git a/test-cases/general-features/src/blog/page.js b/test-cases/general-features/src/blog/page.js index 13062bac..b9fc76af 100644 --- a/test-cases/general-features/src/blog/page.js +++ b/test-cases/general-features/src/blog/page.js @@ -1,5 +1,5 @@ /** - * @import { AsyncLayoutFunction } from '../../../../index.js' + * @import { AsyncLayoutFunction } from '#types' */ import { html } from 'htm/preact' import { dirname, basename } from 'node:path' diff --git a/test-cases/general-features/src/feeds.template.js b/test-cases/general-features/src/feeds.template.js index 6cf6154a..827e2976 100644 --- a/test-cases/general-features/src/feeds.template.js +++ b/test-cases/general-features/src/feeds.template.js @@ -1,21 +1,25 @@ +/** + * @import { TemplateAsyncIterator } from '#types' + */ import pMap from 'p-map' // @ts-ignore import jsonfeedToAtom from 'jsonfeed-to-atom' /** - * @type {import('../../../index.js').TemplateAsyncIterator<{ - * title: string, - * layout: string, - * siteName: string, - * homePageUrl: string, - * authorName: string, - * authorUrl: string, - * authorImgUrl: string, - * publishDate: string, - * siteDescription: string, - * globalDataSentinel: string, - * }>} + * @typedef FeedTemplateVars + * @property {string} title + * @property {string} layout + * @property {string} siteName + * @property {string} homePageUrl + * @property {string} authorName + * @property {string} authorUrl + * @property {string} authorImgUrl + * @property {string} publishDate + * @property {string} siteDescription + * @property {string} globalDataSentinel */ + +/** @type {TemplateAsyncIterator} */ export default async function * feedsTemplate ({ vars: { siteName, diff --git a/test-cases/general-features/src/global.data.js b/test-cases/general-features/src/global.data.js index db26d76e..bce6485c 100644 --- a/test-cases/general-features/src/global.data.js +++ b/test-cases/general-features/src/global.data.js @@ -1,5 +1,5 @@ /** - * @import { AsyncGlobalDataFunction } from '../../../index.js' + * @import { AsyncGlobalDataFunction } from '#types' */ import { html } from 'htm/preact' diff --git a/test-cases/general-features/src/layouts/blog.layout.js b/test-cases/general-features/src/layouts/blog.layout.js index 5a7d1241..c1bb6369 100644 --- a/test-cases/general-features/src/layouts/blog.layout.js +++ b/test-cases/general-features/src/layouts/blog.layout.js @@ -1,5 +1,5 @@ /** - * @import {LayoutFunction} from '../../../../index.js' + * @import {LayoutFunction} from '#types' * @import { SiteVars } from './root.layout.js' */ diff --git a/test-cases/general-features/src/layouts/root.layout.js b/test-cases/general-features/src/layouts/root.layout.js index bacd5aaf..bac5a138 100644 --- a/test-cases/general-features/src/layouts/root.layout.js +++ b/test-cases/general-features/src/layouts/root.layout.js @@ -1,5 +1,5 @@ /** - * @import { LayoutFunction } from '../../../../index.js' + * @import { LayoutFunction } from '#types' */ import { html } from 'htm/preact' diff --git a/test-cases/general-features/src/layouts/ts.layout.ts b/test-cases/general-features/src/layouts/ts.layout.ts index 14da139a..8621837b 100644 --- a/test-cases/general-features/src/layouts/ts.layout.ts +++ b/test-cases/general-features/src/layouts/ts.layout.ts @@ -1,6 +1,6 @@ import defaultRootLayout from './root.layout.js' import { html } from 'htm/preact' -import type { LayoutFunction } from '../../../../index.js' +import type { LayoutFunction } from '#types' import type { SiteVars } from './root.layout.js' const tsLayout: LayoutFunction = (layoutVars) => { diff --git a/test-cases/general-features/src/templates/async-iterator.template.js b/test-cases/general-features/src/templates/async-iterator.template.js index 156053d8..377d5bd4 100644 --- a/test-cases/general-features/src/templates/async-iterator.template.js +++ b/test-cases/general-features/src/templates/async-iterator.template.js @@ -1,9 +1,14 @@ /** - * @type {import('../../../../index.js').TemplateAsyncIterator<{ - * foo: string, - * testVar: string - * }>} + * @import { TemplateAsyncIterator } from '#types' */ + +/** + * @typedef AsyncIteratorTemplateVars + * @property {string} foo + * @property {string} testVar + */ + +/** @type {TemplateAsyncIterator} */ export default async function * ({ vars: { foo, diff --git a/test-cases/general-features/src/templates/object-array.template.js b/test-cases/general-features/src/templates/object-array.template.js index d55e8845..099cb822 100644 --- a/test-cases/general-features/src/templates/object-array.template.js +++ b/test-cases/general-features/src/templates/object-array.template.js @@ -1,9 +1,14 @@ /** - * @type {import('../../../../index.js').TemplateFunction<{ - * foo: string, - * testVar: string - * }>} + * @import { TemplateFunction } from '#types' */ + +/** + * @typedef ObjectArrayTemplateVars + * @property {string} foo + * @property {string} testVar + */ + +/** @type {TemplateFunction} */ export default async function objectArrayTemplate ({ vars: { foo, diff --git a/test-cases/general-features/src/templates/simple.txt.template.js b/test-cases/general-features/src/templates/simple.txt.template.js index 23a6032e..e4cf12d3 100644 --- a/test-cases/general-features/src/templates/simple.txt.template.js +++ b/test-cases/general-features/src/templates/simple.txt.template.js @@ -1,9 +1,14 @@ /** - * @type {import('../../../../index.js').TemplateFunction<{ - * foo: string, - * testVar: string - * }>} + * @import { TemplateFunction } from '#types' */ + +/** + * @typedef SimpleTemplateVars + * @property {string} foo + * @property {string} testVar + */ + +/** @type {TemplateFunction} */ export default async ({ vars: { foo, diff --git a/test-cases/general-features/src/templates/single-object.template.js b/test-cases/general-features/src/templates/single-object.template.js index 0a100270..19bde220 100644 --- a/test-cases/general-features/src/templates/single-object.template.js +++ b/test-cases/general-features/src/templates/single-object.template.js @@ -1,8 +1,13 @@ /** - * @type {import('../../../../index.js').TemplateFunction<{ - * foo: string, - * }>} + * @import { TemplateFunction } from '#types' */ + +/** + * @typedef SingleObjectTemplateVars + * @property {string} foo + */ + +/** @type {TemplateFunction} */ export default async ({ vars: { foo }, }) => ({ diff --git a/test-cases/type-exports/index.test.js b/test-cases/type-exports/index.test.js deleted file mode 100644 index ac0ab5dd..00000000 --- a/test-cases/type-exports/index.test.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check -import { test } from 'node:test' -import assert from 'node:assert' -import { PageData } from '../../index.js' - -/** - * Smoke test that all public types are importable from the package entry point. - * The type imports below are verified by TypeScript at compile time via `npm run test:tsc`. - * - * @typedef {import('../../index.js').PageInfo} PageInfo - * @typedef {import('../../index.js').TemplateInfo} TemplateInfo - * @typedef {import('../../index.js').LayoutFunctionParams} LayoutFunctionParams - * @typedef {import('../../index.js').GlobalDataFunctionParams} GlobalDataFunctionParams - * @typedef {import('../../index.js').PageFunctionParams} PageFunctionParams - * @typedef {import('../../index.js').TemplateFunctionParams} TemplateFunctionParams - */ - -test('PageData is importable from the package entry point', () => { - assert.strictEqual(typeof PageData, 'function', 'PageData is a class') -}) diff --git a/test-cases/type-exports/index.test.ts b/test-cases/type-exports/index.test.ts new file mode 100644 index 00000000..28f7f3c2 --- /dev/null +++ b/test-cases/type-exports/index.test.ts @@ -0,0 +1,133 @@ +import { test } from 'node:test' +import assert from 'node:assert' +import { PageData } from '../../index.js' +import type { + AsyncGlobalDataFunction, + AsyncLayoutFunction, + AsyncPageFunction, + BuildOptions, + DomStackOpts, + GlobalDataFunction, + GlobalDataFunctionParams, + LayoutFunction, + LayoutFunctionParams, + PageFunction, + PageFunctionParams, + PageInfo, + Results, + SiteData, + TemplateAsyncIterator, + TemplateFunction, + TemplateFunctionParams, + TemplateInfo, + TemplateOutputOverride, + TestBuildResult, +} from '#types' + +const walkerFile = { + root: '/src', + filepath: '/src/index.html', + relname: 'index.html', + basename: 'index.html', + parentName: '', +} + +const pageInfo: PageInfo = { + pageFile: { ...walkerFile, type: 'html' }, + type: 'html', + path: '', + url: '/', + outputName: 'index.html', + outputRelname: 'index.html', + draft: false, +} + +const templateInfo: TemplateInfo = { + templateFile: walkerFile, + path: 'feeds', + outputName: 'feed.xml', +} + +const pageData = new PageData({ + pageInfo, + globalVars: {}, + globalStyle: undefined, + globalClient: undefined, + defaultStyle: null, + defaultClient: null, + builderOptions: {}, +}) + +const layoutParams: LayoutFunctionParams, string, string> = { + vars: { title: 'Hello' }, + children: 'Body', + page: pageInfo, + pages: [pageData], +} + +const pageParams: PageFunctionParams, string> = { + vars: { title: 'Hello' }, + page: pageInfo, + pages: [pageData], +} + +const templateParams: TemplateFunctionParams> = { + vars: { siteName: 'DomStack' }, + template: templateInfo, + pages: [pageData], +} + +const globalDataParams: GlobalDataFunctionParams = { + pages: [pageData], +} + +const layoutFunction: LayoutFunction<{ title: string }, string, string> = ({ vars, children }) => `${vars.title}: ${children}` +const asyncLayoutFunction: AsyncLayoutFunction<{ title: string }, string, string> = async ({ vars, children }) => `${vars.title}: ${children}` +const pageFunction: PageFunction<{ title: string }, string> = ({ vars }) => vars.title +const asyncPageFunction: AsyncPageFunction<{ title: string }, string> = async ({ vars }) => vars.title +const templateFunction: TemplateFunction<{ siteName: string }> = async ({ vars }) => vars.siteName +const templateAsyncIterator: TemplateAsyncIterator<{ siteName: string }> = async function * ({ vars }) { + yield { content: vars.siteName, outputName: 'site-name.txt' } +} +const globalDataFunction: GlobalDataFunction<{ generated: true }> = () => ({ generated: true }) +const asyncGlobalDataFunction: AsyncGlobalDataFunction<{ generated: true }> = async () => ({ generated: true }) + +const templateOutputOverride: TemplateOutputOverride = { + content: 'Hello', + outputName: 'hello.txt', +} + +const buildOptions: BuildOptions = { + bundle: true, +} + +const domStackOpts: DomStackOpts = { + static: true, +} + +const siteData: SiteData | null = null +const results: Results | null = null +const testBuildResult: TestBuildResult | null = null + +void layoutParams +void pageParams +void templateParams +void globalDataParams +void layoutFunction +void asyncLayoutFunction +void pageFunction +void asyncPageFunction +void templateFunction +void templateAsyncIterator +void globalDataFunction +void asyncGlobalDataFunction +void templateOutputOverride +void buildOptions +void domStackOpts +void siteData +void results +void testBuildResult + +test('PageData is importable from the package entry point', () => { + assert.strictEqual(typeof PageData, 'function', 'PageData is a class') +}) diff --git a/tsconfig.json b/tsconfig.json index 923517ac..1f80327a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,8 @@ "skipLibCheck": true, "jsx": "react-jsx", "jsxImportSource": "preact", + "allowImportingTsExtensions": true, + "rewriteRelativeImportExtensions": true, "typeRoots": ["./types", "./node_modules/@types"] }, "include": [ @@ -11,7 +13,8 @@ "lib/**/*", "test-cases/**/*", "index.js", - "bin.js" + "bin.js", + "types.ts" ], "exclude": [ "node_modules", diff --git a/types.ts b/types.ts new file mode 100644 index 00000000..37059fb7 --- /dev/null +++ b/types.ts @@ -0,0 +1,37 @@ +// Type-only public entry for `import type { ... } from '@domstack/static/types.js'`. +// There is intentionally no runtime `types.js` today; this source emits `types.d.ts`, +// and `types.js` is reserved for a future runtime/type companion entry if needed. +import type { Results } from './lib/builder.js' + +export type { BuildOptions } from 'esbuild' +export type { DomStackOpts, Results, SiteData } from './lib/builder.js' +export type { + AsyncGlobalDataFunction, + GlobalDataFunction, + GlobalDataFunctionParams, +} from './lib/build-pages/index.js' +export type { + AsyncLayoutFunction, + LayoutFunction, + LayoutFunctionParams, + PageData, +} from './lib/build-pages/page-data.js' +export type { + AsyncPageFunction, + PageFunction, + PageFunctionParams, +} from './lib/build-pages/page-builders/page-writer.js' +export type { + TemplateAsyncIterator, + TemplateFunction, + TemplateFunctionParams, + TemplateOutputOverride, +} from './lib/build-pages/page-builders/template-builder.js' +export type { PageInfo, TemplateInfo } from './lib/identify-pages.js' + +export type TestBuildResult = { + dest: string + results: Results + readOutput: (path: string) => Promise + cleanup: () => Promise +}