Files
upstream-tldraw/internal/scripts/product-manifest.ts
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

70 lines
2.6 KiB
TypeScript

import { join } from 'path'
import { REPO_ROOT, readJsonIfExists } from './lib/file'
import { PRODUCT_CONFIG_KEY, ProductConfig } from './lib/types'
import { getAllWorkspacePackages } from './lib/workspace'
interface ManifestComponent extends ProductConfig {
packages: { name: string; description?: string }[]
features: ManifestComponent[]
}
/**
* Prints the product manifest: the commercial components customers license, as a tree. Top-level
* entries are order form line items; their `features` are the parts that can be licensed
* individually, listed indented beneath them on the order form.
*
* This is the aggregate view of the `tldraw_product` fields in each package's package.json — those
* fields are the source of truth, and are validated by `yarn check-packages`. See
* internal/docs/product-stable-ids.md.
*/
async function main() {
const lernaJson = (await readJsonIfExists(join(REPO_ROOT, 'lerna.json'))) as {
version: string
} | null
if (!lernaJson) throw new Error('Could not read lerna.json')
const componentsById = new Map<string, ManifestComponent>()
for (const { packageJson, relativePath } of await getAllWorkspacePackages()) {
if (!relativePath.startsWith('packages/') || packageJson.private) continue
const product = packageJson[PRODUCT_CONFIG_KEY]
if (!product) continue
// packages sharing a stable id are required to have identical product metadata; this is
// enforced by `yarn check-packages`, so taking the first package's config here is safe
const component = componentsById.get(product.stableId) ?? {
...product,
packages: [],
features: [],
}
component.packages.push({
name: packageJson.name,
description: packageJson.description,
})
componentsById.set(product.stableId, component)
}
const byName = (a: { name: string }, b: { name: string }) => a.name.localeCompare(b.name)
const all = [...componentsById.values()].sort(byName)
for (const component of all) {
component.packages.sort(byName)
}
// nest features under the component they belong to. `check-packages` guarantees every parent
// resolves, so nothing can be silently dropped here.
for (const component of all) {
if (component.parent) {
componentsById.get(component.parent)!.features.push(component)
}
}
// the standard offering leads, then the premium modules, matching the order form's layout
const products = all
.filter((component) => !component.parent)
.sort((a, b) => Number(a.premium) - Number(b.premium) || byName(a, b))
// eslint-disable-next-line no-console
console.log(JSON.stringify({ version: lernaJson.version, products }, null, '\t'))
}
main()