@monimesl/dot-cli 0.1.0-alpha.9 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -59
- package/dist/cli.js +530 -339
- package/dist/cli.js.map +1 -1
- package/dist/{server-BfPAnsSf.js → server-DMnWDdJ6.js} +570 -478
- package/dist/server-DMnWDdJ6.js.map +1 -0
- package/dist/templates/showcase/dot.ts +53 -16
- package/dist/templates/showcase/pages/basics/bars/controller.ts +47 -0
- package/dist/templates/showcase/pages/basics/bars/state.ts +7 -0
- package/dist/templates/showcase/pages/basics/bars/view.dml +36 -0
- package/dist/templates/showcase/pages/{text → basics/bindings}/controller.ts +5 -0
- package/dist/templates/showcase/pages/basics/bindings/state.ts +14 -0
- package/dist/templates/showcase/pages/basics/bindings/view.dml +41 -0
- package/dist/templates/showcase/pages/basics/colors/controller.ts +112 -0
- package/dist/templates/showcase/pages/basics/colors/palette.ts +52 -0
- package/dist/templates/showcase/pages/basics/colors/state.ts +17 -0
- package/dist/templates/showcase/pages/basics/colors/view.dml +142 -0
- package/dist/templates/showcase/pages/basics/concert/controller.ts +16 -0
- package/dist/templates/showcase/pages/basics/concert/state.ts +7 -0
- package/dist/templates/showcase/pages/basics/concert/view.dml +20 -0
- package/dist/templates/showcase/pages/basics/control-flow/controller.ts +18 -0
- package/dist/templates/showcase/pages/basics/control-flow/state.ts +16 -0
- package/dist/templates/showcase/pages/basics/control-flow/view.dml +55 -0
- package/dist/templates/showcase/pages/basics/events/controller.ts +43 -0
- package/dist/templates/showcase/pages/basics/events/state.ts +11 -0
- package/dist/templates/showcase/pages/basics/events/view.dml +51 -0
- package/dist/templates/showcase/pages/basics/hooks/controller.ts +43 -0
- package/dist/templates/showcase/pages/basics/hooks/state.ts +10 -0
- package/dist/templates/showcase/pages/basics/hooks/view.dml +37 -0
- package/dist/templates/showcase/pages/basics/navigation/controller.ts +41 -0
- package/dist/templates/showcase/pages/basics/navigation/state.ts +11 -0
- package/dist/templates/showcase/pages/basics/navigation/view.dml +48 -0
- package/dist/templates/showcase/pages/basics/pick-genre/controller.ts +18 -0
- package/dist/templates/showcase/pages/basics/pick-genre/state.ts +3 -0
- package/dist/templates/showcase/pages/basics/pick-genre/view.dml +10 -0
- package/dist/templates/showcase/pages/basics/share/concerts.ts +31 -0
- package/dist/templates/showcase/pages/basics/share/controller.ts +12 -0
- package/dist/templates/showcase/pages/basics/share/state.ts +5 -0
- package/dist/templates/showcase/pages/basics/share/view.dml +21 -0
- package/dist/templates/showcase/pages/{state → basics/state}/controller.ts +1 -0
- package/dist/templates/showcase/pages/basics/state/view.dml +46 -0
- package/dist/templates/showcase/pages/{carousel → components/carousel}/controller.ts +2 -1
- package/dist/templates/showcase/pages/{carousel → components/carousel}/state.ts +5 -5
- package/dist/templates/showcase/pages/{carousel → components/carousel}/view.dml +7 -5
- package/dist/templates/showcase/pages/{feedback → components/feedback}/controller.ts +13 -2
- package/dist/templates/showcase/pages/components/feedback/state.ts +41 -0
- package/dist/templates/showcase/pages/{feedback → components/feedback}/view.dml +38 -9
- package/dist/templates/showcase/pages/{forms → components/forms}/controller.ts +23 -19
- package/dist/templates/showcase/pages/{forms → components/forms}/state.ts +6 -3
- package/dist/templates/showcase/pages/components/forms/view.dml +97 -0
- package/dist/templates/showcase/pages/components/icons/controller.ts +15 -0
- package/dist/templates/showcase/pages/components/icons/state.ts +75 -0
- package/dist/templates/showcase/pages/components/icons/view.dml +36 -0
- package/dist/templates/showcase/pages/{images → components/images}/controller.ts +4 -1
- package/dist/templates/showcase/pages/components/images/view.dml +83 -0
- package/dist/templates/showcase/pages/{layout → components/layout}/controller.ts +3 -2
- package/dist/templates/showcase/pages/components/layout/view.dml +143 -0
- package/dist/templates/showcase/pages/components/lists/controller.ts +18 -0
- package/dist/templates/showcase/pages/{lists → components/lists}/state.ts +43 -30
- package/dist/templates/showcase/pages/components/lists/view.dml +88 -0
- package/dist/templates/showcase/pages/{payments → components/money}/controller.ts +7 -8
- package/dist/templates/showcase/pages/components/money/view.dml +54 -0
- package/dist/templates/showcase/pages/components/reading/controller.ts +6 -0
- package/dist/templates/showcase/pages/components/reading/state.ts +23 -0
- package/dist/templates/showcase/pages/components/reading/view.dml +42 -0
- package/dist/templates/showcase/pages/{lists → components/sheets}/controller.ts +10 -11
- package/dist/templates/showcase/pages/components/sheets/state.ts +26 -0
- package/dist/templates/showcase/pages/components/sheets/view.dml +38 -0
- package/dist/templates/showcase/pages/components/styles/controller.ts +6 -0
- package/dist/templates/showcase/pages/components/styles/state.ts +3 -0
- package/dist/templates/showcase/pages/components/styles/view.dml +101 -0
- package/dist/templates/showcase/pages/components/tabs/controller.ts +41 -0
- package/dist/templates/showcase/pages/{filters → components/tabs}/state.ts +32 -23
- package/dist/templates/showcase/pages/components/tabs/view.dml +57 -0
- package/dist/templates/showcase/pages/components/text/controller.ts +10 -0
- package/dist/templates/showcase/pages/components/text/state.ts +3 -0
- package/dist/templates/showcase/pages/components/text/view.dml +95 -0
- package/dist/templates/showcase/pages/dash/account/controller.ts +32 -0
- package/dist/templates/showcase/pages/dash/account/state.ts +9 -0
- package/dist/templates/showcase/pages/dash/account/view.dml +33 -0
- package/dist/templates/showcase/pages/{cache → dash/cache}/controller.ts +9 -4
- package/dist/templates/showcase/pages/dash/cache/view.dml +48 -0
- package/dist/templates/showcase/pages/dash/calls/controller.ts +67 -0
- package/dist/templates/showcase/pages/dash/calls/state.ts +9 -0
- package/dist/templates/showcase/pages/dash/calls/view.dml +69 -0
- package/dist/templates/showcase/pages/dash/contacts/controller.ts +30 -0
- package/dist/templates/showcase/pages/dash/contacts/state.ts +6 -0
- package/dist/templates/showcase/pages/dash/contacts/view.dml +33 -0
- package/dist/templates/showcase/pages/dash/crypto/controller.ts +38 -0
- package/dist/templates/showcase/pages/dash/crypto/state.ts +10 -0
- package/dist/templates/showcase/pages/dash/crypto/view.dml +48 -0
- package/dist/templates/showcase/pages/{files → dash/files}/controller.ts +7 -2
- package/dist/templates/showcase/pages/{files → dash/files}/state.ts +4 -0
- package/dist/templates/showcase/pages/dash/files/view.dml +78 -0
- package/dist/templates/showcase/pages/dash/media/controller.ts +65 -0
- package/dist/templates/showcase/pages/dash/media/state.ts +12 -0
- package/dist/templates/showcase/pages/dash/media/view.dml +53 -0
- package/dist/templates/showcase/pages/{network → dash/network}/controller.ts +84 -20
- package/dist/templates/showcase/pages/{network → dash/network}/state.ts +14 -1
- package/dist/templates/showcase/pages/dash/network/view.dml +108 -0
- package/dist/templates/showcase/pages/dash/payments/cases.ts +445 -0
- package/dist/templates/showcase/pages/dash/payments/controller.ts +149 -0
- package/dist/templates/showcase/pages/dash/payments/state.ts +33 -0
- package/dist/templates/showcase/pages/dash/payments/view.dml +71 -0
- package/dist/templates/showcase/pages/{secrets → dash/secrets}/controller.ts +2 -1
- package/dist/templates/showcase/pages/dash/secrets/view.dml +26 -0
- package/dist/templates/showcase/pages/dash/system/controller.ts +89 -0
- package/dist/templates/showcase/pages/dash/system/state.ts +13 -0
- package/dist/templates/showcase/pages/dash/system/view.dml +96 -0
- package/dist/templates/showcase/pages/dash/ui/controller.ts +70 -0
- package/dist/templates/showcase/pages/dash/ui/state.ts +8 -0
- package/dist/templates/showcase/pages/dash/ui/view.dml +31 -0
- package/dist/templates/showcase/pages/index/controller.ts +1 -1
- package/dist/templates/showcase/pages/index/state.ts +175 -60
- package/dist/templates/showcase/pages/index/view.dml +6 -3
- package/package.json +6 -6
- package/dist/server-BfPAnsSf.js.map +0 -1
- package/dist/templates/showcase/pages/cache/view.dml +0 -36
- package/dist/templates/showcase/pages/device/controller.ts +0 -80
- package/dist/templates/showcase/pages/device/state.ts +0 -7
- package/dist/templates/showcase/pages/device/view.dml +0 -49
- package/dist/templates/showcase/pages/feedback/state.ts +0 -8
- package/dist/templates/showcase/pages/files/view.dml +0 -50
- package/dist/templates/showcase/pages/filters/controller.ts +0 -27
- package/dist/templates/showcase/pages/filters/view.dml +0 -44
- package/dist/templates/showcase/pages/forms/view.dml +0 -49
- package/dist/templates/showcase/pages/images/view.dml +0 -53
- package/dist/templates/showcase/pages/layout/view.dml +0 -103
- package/dist/templates/showcase/pages/lists/view.dml +0 -59
- package/dist/templates/showcase/pages/navigation/controller.ts +0 -65
- package/dist/templates/showcase/pages/navigation/state.ts +0 -17
- package/dist/templates/showcase/pages/navigation/view.dml +0 -34
- package/dist/templates/showcase/pages/network/view.dml +0 -67
- package/dist/templates/showcase/pages/payments/view.dml +0 -45
- package/dist/templates/showcase/pages/secrets/view.dml +0 -24
- package/dist/templates/showcase/pages/state/view.dml +0 -33
- package/dist/templates/showcase/pages/text/state.ts +0 -8
- package/dist/templates/showcase/pages/text/view.dml +0 -58
- /package/dist/templates/showcase/pages/{state → basics/state}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{images → components/images}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{layout → components/layout}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{payments → components/money}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{cache → dash/cache}/state.ts +0 -0
- /package/dist/templates/showcase/pages/{secrets → dash/secrets}/state.ts +0 -0
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/report.ts","../src/create/template.ts","../src/create/create.ts","../src/dot-root.ts","../src/create/page.ts","../src/create/package-manager.ts","../src/device/developer-key.ts","../src/device/server.ts","../src/simulator.ts","../src/dev.ts","../src/preview.ts","../src/prompts.ts","../src/cli.ts"],"sourcesContent":["import { DmlParseError } from '@monimesl/dot-dml-parser';\nimport type { BuildResult } from '@monimesl/dot-compiler';\nimport { CompileError } from '@monimesl/dot-compiler';\nimport { ScriptParseError } from '@monimesl/dot-script-parser';\n\n/** A mistake in how a command was used, which its message alone explains. */\nexport class CommandError extends Error {\n override readonly name = 'CommandError';\n}\n\nexport function describeError(error: unknown): string {\n const known =\n error instanceof CommandError ||\n error instanceof CompileError ||\n error instanceof DmlParseError ||\n error instanceof ScriptParseError;\n if (known) {\n return error.message;\n }\n if ((error as { code?: string }).code?.startsWith('ERR_PARSE_ARGS')) {\n // Node's message goes on to explain `--` for positional arguments, which is noise here.\n const [firstSentence] = (error as Error).message.split('. ');\n return `${firstSentence}. See dotctl --help.`;\n }\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\nexport function printWarnings({ warnings }: BuildResult): void {\n for (const warning of warnings) {\n console.warn(`warning: ${warning.message}`);\n }\n}\n\nexport function printBuildTime(startedAt: number): void {\n console.log(`Built in ${Math.round(performance.now() - startedAt)}ms`);\n}\n","export const TEMPLATES = ['starter', 'showcase'] as const;\n\nexport type Template = (typeof TEMPLATES)[number];\n\n// What each template starts a dot with.\nexport const TEMPLATE_HINTS: Record<Template, string> = {\n starter: 'one page to build on',\n showcase: 'a page for each feature, to read',\n};\n\nexport function isTemplate(name: string): name is Template {\n return (TEMPLATES as readonly string[]).includes(name);\n}\n\ninterface TemplateOptions {\n name: string;\n packageName: string;\n dotVersion: string;\n workspace: boolean;\n template: Template;\n}\n\nexport const PAGE_FILES: Readonly<Record<string, string>> = {\n 'view.dml': '<View>\\n\\t<Text>My new page</Text>\\n</View>\\n',\n 'state.ts': 'export default {};\\n',\n 'controller.ts': `import state from './state';\n\nexport default definePage({\n initialState: state,\n});\n`,\n};\n\n// The dot itself is copied from the template's example; these are the files around it.\nexport const TEMPLATE_FILES = ['dot.ts', 'pages', 'statics', '.env'] as const;\n\n// For editors that follow `$schema`, they can check dot.json and complete its fields.\nconst DOT_JSON_SCHEMA = './node_modules/@monimesl/dot-runtime/dot.schema.json';\n\nconst json = (value: unknown) => `${JSON.stringify(value, null, 2)}\\n`;\n\nexport function projectFiles(options: TemplateOptions): Record<string, string> {\n return {\n 'package.json': packageJson(options),\n 'tsconfig.json': tsconfig(options),\n '.gitignore': 'node_modules/\\ndist/\\n# Types generated by dotctl\\n.dot/\\n',\n 'dot.json': dotJson(options),\n 'README.md': readme(options),\n };\n}\n\nfunction packageJson({ packageName, dotVersion, workspace }: TemplateOptions): string {\n const conditions = workspace ? ' --conditions @monimesl/dot-source' : '';\n return json({\n name: packageName,\n private: true,\n type: 'module',\n scripts: {\n dev: `dotctl dev${conditions}`,\n build: `dotctl build${conditions}`,\n preview: `dotctl preview${conditions}`,\n typecheck: 'tsc --noEmit',\n },\n dependencies: { '@monimesl/dot-runtime': dotVersion },\n devDependencies: { '@monimesl/dot-cli': dotVersion, typescript: '^5.9.3' },\n });\n}\n\nfunction tsconfig({ workspace }: TemplateOptions): string {\n const compilerOptions: Record<string, unknown> = {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['@monimesl/dot-runtime/globals'],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n verbatimModuleSyntax: true,\n };\n if (workspace) {\n compilerOptions.customConditions = ['@monimesl/dot-source'];\n }\n return json({\n compilerOptions,\n include: ['dot.ts', 'pages', '.dot/pages.d.ts', '.dot/env.d.ts'],\n });\n}\n\nfunction dotJson({ name, packageName, template }: TemplateOptions): string {\n const dot: Record<string, unknown> = {\n $schema: DOT_JSON_SCHEMA,\n id: `com.example.${idWord(packageName)}`,\n name,\n version: '0.1.0',\n };\n if (template === 'showcase') {\n // The showcase's network page reaches these.\n dot.network = { hosts: ['itunes.apple.com', '*.mzstatic.com', 'httpbin.org'] };\n }\n return json(dot);\n}\n\nconst TEMPLATE_READMES: Readonly<Record<Template, string>> = {\n starter: `It starts with one page, \\`index\\`: a greeting from \\`.env\\` and a count to tap. Change it,\nand add pages as the dot grows. \\`npx dotctl create my-tour --template showcase\\` makes a dot with a\npage for each feature, to read how each is done.`,\n showcase: `It starts as a showcase: \\`index\\` lists a page for each feature, from layout, text, images and\ninputs to state, navigation, and Dash's alerts, network and files. Read a page to see how it's\ndone, then delete the ones you don't need, from \\`pages/\\` and from \\`dot.ts\\`.`,\n};\n\nfunction readme({ name, template }: TemplateOptions): string {\n return `# ${name}\n\nA dot: a mini app that runs inside Dash.\n\n\\`\\`\\`sh\nnpm install\nnpm run dev # run it in the simulator; it reloads on every change\nnpm run build # build it for Dash\n\\`\\`\\`\n\nEach page is a folder under \\`pages/\\` with three files: \\`view.dml\\` (what it shows),\n\\`state.ts\\` (what it starts with) and \\`controller.ts\\` (how it changes). A page's markup is one\nroot \\`<View>\\` with everything else inside it. \\`npx dotctl create page <path>\\` adds a page, such\nas \\`cart/checkout\\`, with the three files to start from, and lists it in \\`dot.ts\\`. The first page\nthere is where the dot starts.\n\n\\`dot.json\\` describes the dot to Dash. Change its \\`id\\` from \\`com.example.…\\` to a reverse domain\nname you own before you publish: it can't change afterwards. Its \\`network.hosts\\` lists every host\nthe dot sends requests to with \\`dash.network\\`; requests to any other fail. Your editor completes\nthe other fields from the schema it points to.\n\n\\`.env\\` holds public configuration, which the service reads as \\`env.GREETING\\`. Every variable\nthere is built into the dot, so anyone who has it can read them: never put a secret there.\n\\`.env.development\\` and \\`.env.production\\` override it for \\`dev\\` and \\`build\\`.\n\n${TEMPLATE_READMES[template]}\n`;\n}\n\n// A word of the dot's id: the package name, which is already lowercase letters, digits and inner\n// hyphens, cut to the 63 characters a host name allows.\nfunction idWord(packageName: string): string {\n return packageName.slice(0, 63).replace(/-+$/, '');\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { cp, mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join, resolve } from 'node:path';\n\nimport { CommandError } from '../report';\nimport type { Template } from './template';\nimport { projectFiles, TEMPLATE_FILES } from './template';\n\ninterface CreateOptions {\n name: string;\n dir: string;\n template?: Template;\n}\n\ninterface CreateResult {\n readonly root: string;\n readonly workspace: boolean;\n}\n\ninterface PackageJson {\n name: string;\n version: string;\n}\n\nexport async function create({\n name,\n dir,\n template = 'starter',\n}: CreateOptions): Promise<CreateResult> {\n const root = resolve(dir);\n if (existsSync(root) && readdirSync(root).length > 0) {\n throw new CommandError(`${dir} already exists and is not empty`);\n }\n const packageName = toPackageName(name);\n if (!packageName) {\n throw new CommandError(`\"${name}\" needs at least one letter or digit`);\n }\n\n const workspace = isInDotWorkspace(root);\n const source = templateDir(template);\n await mkdir(root, { recursive: true });\n for (const path of TEMPLATE_FILES) {\n await cp(join(source, path), join(root, path), { recursive: true });\n }\n const generated = projectFiles({\n name,\n packageName,\n dotVersion: workspace ? 'workspace:*' : `^${cliVersion()}`,\n workspace,\n template,\n });\n for (const [path, content] of Object.entries(generated)) {\n await writeFile(join(root, path), content);\n }\n return { root, workspace };\n}\n\nexport function toPackageName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nexport function toDisplayName(dir: string): string {\n return basename(resolve(dir))\n .split(/[-_\\s]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n// True when the nearest pnpm workspace above `dir` is the Dot repository.\nexport function isInDotWorkspace(dir: string): boolean {\n let current = dirname(dir);\n while (true) {\n if (existsSync(join(current, 'pnpm-workspace.yaml'))) {\n const runtimeManifest = join(current, 'packages/runtime/package.json');\n if (!existsSync(runtimeManifest)) {\n return false;\n }\n return readPackageJson(runtimeManifest).name === '@monimesl/dot-runtime';\n }\n const parent = dirname(current);\n if (parent === current) {\n return false;\n }\n current = parent;\n }\n}\n\n// The template's example: read from the repository, or from the copy the published CLI ships.\nfunction templateDir(template: Template): string {\n const example = join(cliRoot(), '../../examples', template);\n return existsSync(example) ? example : join(cliRoot(), 'dist/templates', template);\n}\n\nfunction cliVersion(): string {\n return readPackageJson(join(cliRoot(), 'package.json')).version;\n}\n\nfunction readPackageJson(path: string): PackageJson {\n return JSON.parse(readFileSync(path, 'utf8')) as PackageJson;\n}\n\nfunction cliRoot(): string {\n return dirname(createRequire(import.meta.url).resolve('@monimesl/dot-cli/package.json'));\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n// The nearest folder at or above `dir` with a dot.json.\nexport function findDotRoot(dir: string): string | undefined {\n while (true) {\n if (existsSync(join(dir, 'dot.json'))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n return undefined;\n }\n dir = parent;\n }\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { isPageId } from '@monimesl/dot-core';\nimport type { DotModuleIR } from '@monimesl/dot-script-parser';\nimport { parseDotModule } from '@monimesl/dot-script-parser';\n\nimport { findDotRoot } from '../dot-root';\nimport { CommandError } from '../report';\nimport { PAGE_FILES } from './template';\n\ninterface CreatePageResult {\n readonly dir: string;\n readonly files: readonly string[];\n // How the page got into `defineDot({ pages })` in dot.ts: `manual` when dot.ts couldn't be\n // changed, so the page still needs listing.\n readonly listing: 'added' | 'already' | 'manual';\n}\n\n// Adds a page to the dot around `cwd`: its folder under pages/, listed last in dot.ts.\nexport async function createPage(path: string, cwd: string): Promise<CreatePageResult> {\n if (!isPageId(path)) {\n throw new CommandError(\n `\"${path}\" is not a page path: use letters, digits, \"-\" and \"_\", with \"/\" between folders, such as \"cart/checkout\"`,\n );\n }\n const root = findDotRoot(resolve(cwd));\n if (root === undefined) {\n throw new CommandError('There is no dot.json here or in a folder above: run it inside a dot');\n }\n const dir = join(root, 'pages', path);\n if (existsSync(dir)) {\n throw new CommandError(`pages/${path} already exists`);\n }\n await mkdir(dir, { recursive: true });\n const files: string[] = [];\n for (const [name, content] of Object.entries(PAGE_FILES)) {\n const file = join(dir, name);\n await writeFile(file, content);\n files.push(file);\n }\n return { dir, files, listing: await listPage(join(root, 'dot.ts'), path) };\n}\n\nasync function listPage(dotFile: string, path: string): Promise<CreatePageResult['listing']> {\n if (!existsSync(dotFile)) {\n return 'manual';\n }\n const source = await readFile(dotFile, 'utf8');\n let dot: DotModuleIR;\n try {\n dot = parseDotModule(source, dotFile);\n } catch {\n return 'manual';\n }\n if (dot.pages.includes(path)) {\n return 'already';\n }\n const updated = withPage(source, dot.lastPage, path);\n if (!listsPage(updated, dotFile, path)) {\n return 'manual';\n }\n await writeFile(dotFile, updated);\n return 'added';\n}\n\n// `source` with `path` after its last page, written as the list is: on a line of its own when each\n// page has one, and in the same quotes.\nfunction withPage(source: string, lastPage: DotModuleIR['lastPage'], path: string): string {\n const quote = source[lastPage.start] === '\"' ? '\"' : \"'\";\n const page = `${quote}${path}${quote}`;\n const lineStart = source.lastIndexOf('\\n', lastPage.start - 1) + 1;\n const indent = source.slice(lineStart, lastPage.start);\n if (!/^\\s*$/.test(indent)) {\n return `${source.slice(0, lastPage.end)}, ${page}${source.slice(lastPage.end)}`;\n }\n const trailingComma = /^\\s*,/.exec(source.slice(lastPage.end));\n if (trailingComma) {\n const end = lastPage.end + trailingComma[0].length;\n return `${source.slice(0, end)}\\n${indent}${page},${source.slice(end)}`;\n }\n return `${source.slice(0, lastPage.end)},\\n${indent}${page}${source.slice(lastPage.end)}`;\n}\n\nfunction listsPage(source: string, dotFile: string, path: string): boolean {\n try {\n return parseDotModule(source, dotFile).pages.includes(path);\n } catch {\n return false;\n }\n}\n","import { spawnSync } from 'node:child_process';\n\nexport const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'] as const;\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\nexport function isPackageManager(name: string): name is PackageManager {\n return (PACKAGE_MANAGERS as readonly string[]).includes(name);\n}\n\nexport function launchedBy(userAgent = process.env.npm_config_user_agent ?? ''): PackageManager {\n return PACKAGE_MANAGERS.find((name) => userAgent.startsWith(`${name}/`)) ?? 'npm';\n}\n\nexport function installedManagers(\n isInstalled: (name: PackageManager) => boolean = onPath,\n): PackageManager[] {\n return PACKAGE_MANAGERS.filter(isInstalled);\n}\n\nfunction onPath(name: PackageManager): boolean {\n return (\n spawnSync(name, ['--version'], { stdio: 'ignore', shell: process.platform === 'win32' })\n .status === 0\n );\n}\n","import { createPrivateKey, createPublicKey, sign } from 'node:crypto';\nimport type { KeyObject } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\n// The Ed25519 key this computer signs its dotdev links with. The developer adds its public key to\n// their account, and Monime checks a link's signature before Dash opens it.\nexport interface DeveloperKey {\n // The raw 32-byte public key, base64: what the developer adds to their account.\n readonly publicKey: string;\n // The lowercase hex of the public key's first 8 bytes, which a link names its key by.\n readonly keyId: string;\n // A base64 signature.\n sign(bytes: Buffer): string;\n}\n\nexport function defaultDeveloperKeyPath(): string {\n return process.env.DOT_DEVELOPER_KEY ?? join(homedir(), '.dot', 'developer-key.pem');\n}\n\n// How to make the key, which dotctl reads but leaves to the developer to create.\nexport function missingDeveloperKeyHint(path = defaultDeveloperKeyPath()): string {\n return (\n ` This computer has no developer key in ${path}, and Dash opens only signed links.\\n` +\n \" Make one with OpenSSL 3 (macOS's own openssl can't; brew install openssl):\\n\\n\" +\n ` mkdir -p ${dirname(path)} && openssl genpkey -algorithm ed25519 -out ${path}\\n\\n` +\n ' Then add the public key `dotctl keys show` prints to your Monime account.'\n );\n}\n\n// Returns undefined when this computer has no key yet.\nexport async function loadDeveloperKey(\n path = defaultDeveloperKeyPath(),\n): Promise<DeveloperKey | undefined> {\n let pem: string;\n try {\n pem = await readFile(path, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return undefined;\n }\n throw error;\n }\n const privateKey = createPrivateKey(pem);\n if (privateKey.asymmetricKeyType !== 'ed25519') {\n throw new Error(`${path} is not an Ed25519 key`);\n }\n return toDeveloperKey(privateKey);\n}\n\nfunction toDeveloperKey(privateKey: KeyObject): DeveloperKey {\n const raw = Buffer.from(createPublicKey(privateKey).export({ format: 'jwk' }).x!, 'base64url');\n return {\n publicKey: raw.toString('base64'),\n keyId: raw.subarray(0, 8).toString('hex'),\n sign: (bytes) => sign(null, bytes, privateKey).toString('base64'),\n };\n}\n","import { createHash, createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readdir, readFile } from 'node:fs/promises';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { networkInterfaces } from 'node:os';\nimport { join, relative, sep } from 'node:path';\n\nimport type { DeveloperKey } from './developer-key';\n\ninterface DeviceServerOptions {\n // Where devices reach the server; the computer's local network address unless set.\n address?: string | undefined;\n // A free port unless set: the link carries it.\n port?: number | undefined;\n // Each line a device sends, such as its dot's console output.\n onLog?: (line: string, from: string) => void;\n onConnect?: (from: string) => void;\n // Signs the link, for hosts such as Dash that open only a known developer's links.\n developerKey?: DeveloperKey | undefined;\n}\n\n// Serves a dot's builds to the example host apps on devices, which follow them and reload.\nexport interface DeviceServer {\n // What a device opens, `dotdev://connect?server=…&secret=…`, as short as it can be for a small QR\n // code. A signed link's signature is at `GET /dev/link`.\n readonly link: string;\n // Serves the build output in `dir` as the newest build. A `hot` build changed only pages, so\n // devices can run it in place, keeping each open page's state.\n publish(dir: string, options?: { hot?: boolean }): Promise<void>;\n // Tells devices the newest build failed; they keep the last good one.\n fail(message: string): void;\n close(): Promise<void>;\n}\n\ninterface Build {\n readonly files: ReadonlyMap<string, { readonly bytes: Buffer; readonly hash: string }>;\n}\n\nconst DEVICE_SCHEME = 'dotdev';\n\n// Devices ask again after this, which keeps a waiting request from outliving a quiet network.\nconst WAIT_MS = 25_000;\nconst MAX_LOG_BYTES = 1024 * 1024;\n// How long a signed link opens, so a photo of an old QR code is no use for long.\nconst LINK_LIFETIME_SECONDS = 12 * 60 * 60;\n\nexport const BUILD_MAC_HEADER = 'dot-build-mac';\n\n// What a signed link's `sig` signs, a line each.\nexport function signedLinkMessage(\n server: string,\n secret: string,\n expires: number,\n keyId: string,\n): string {\n return ['dotdev-connect', server, secret, String(expires), keyId].join('\\n');\n}\n\n// What a device sends as its bearer token, made from the link's secret so the link needn't carry it.\n// Seeing it on the network gives away nothing of the secret.\nexport function deviceToken(secret: string): string {\n return createHmac('sha256', Buffer.from(secret, 'base64url'))\n .update('dotdev-token', 'utf8')\n .digest('base64url');\n}\n\n// A signed link's signature, which `GET /dev/link` serves: what isn't secret stays out of the QR code.\nexport interface LinkSignature {\n readonly expires: number;\n readonly keyId: string;\n // Base64.\n readonly sig: string;\n}\n\n// The HMAC-SHA256 of a build listing, keyed with the link's secret: a device takes only listings\n// from whoever has the link, and each file has to match its hash in the listing.\nexport function buildMac(secret: string, body: string): string {\n return createHmac('sha256', Buffer.from(secret, 'base64url'))\n .update(`dotdev-build\\n${body}`, 'utf8')\n .digest('base64url');\n}\n\nexport async function startDeviceServer({\n address = localNetworkAddress(),\n port = 0,\n onLog = () => {},\n onConnect = () => {},\n developerKey,\n}: DeviceServerOptions = {}): Promise<DeviceServer> {\n if (address === undefined) {\n throw new Error('This computer has no local network address for devices to reach it on');\n }\n // It never goes over the network: only the link carries it.\n const secret = randomBytes(16).toString('base64url');\n const token = deviceToken(secret);\n let signature: LinkSignature | null = null;\n let build: Build = { files: new Map() };\n let generation = 0;\n // The oldest generation from which only hot builds lead to the newest: a device on it, or on a\n // later one, can take the newest in place.\n let hotSince = 0;\n let error: string | null = null;\n const waiting = new Set<() => void>();\n const connected = new Set<string>();\n\n const announce = () => {\n generation += 1;\n for (const wake of waiting) {\n wake();\n }\n };\n\n const server = createServer((request, response) => {\n const from = request.socket.remoteAddress ?? 'a device';\n // Before the token: a device needs the signature to check the link before it uses it, and the\n // signature is no secret.\n if (request.method === 'GET' && request.url === '/dev/link') {\n if (signature) {\n sendJson(response, signature);\n } else {\n response.writeHead(404).end();\n }\n return;\n }\n if (!isAuthorized(request, token)) {\n response.writeHead(401).end();\n return;\n }\n const url = new URL(request.url ?? '/', 'http://device');\n const path = url.pathname;\n if (request.method === 'GET' && path === '/dev/build') {\n if (!connected.has(from)) {\n connected.add(from);\n onConnect(from);\n }\n const files = Object.fromEntries([...build.files].map(([name, file]) => [name, file.hash]));\n const body = JSON.stringify({ generation, hotSince, files, error });\n response\n .writeHead(200, {\n 'content-type': 'application/json',\n [BUILD_MAC_HEADER]: buildMac(secret, body),\n })\n .end(body);\n } else if (request.method === 'GET' && path.startsWith('/dev/files/')) {\n if (url.searchParams.get('generation') !== String(generation)) {\n response.writeHead(409).end();\n return;\n }\n const name = path.slice('/dev/files/'.length).split('/').map(decodeURIComponent).join('/');\n const file = build.files.get(name);\n if (!file) {\n response.writeHead(404).end();\n return;\n }\n response.writeHead(200, { 'content-type': 'application/octet-stream' }).end(file.bytes);\n } else if (request.method === 'GET' && path === '/dev/changes') {\n waitForChange(response, Number(url.searchParams.get('after')));\n } else if (request.method === 'POST' && path === '/dev/log') {\n readText(request)\n .then((text) => {\n for (const line of text.split('\\n')) {\n onLog(line, from);\n }\n response.writeHead(204).end();\n })\n .catch(() => response.writeHead(413).end());\n } else {\n response.writeHead(404).end();\n }\n });\n\n const waitForChange = (response: ServerResponse, after: number) => {\n if (generation > after) {\n sendJson(response, { generation });\n return;\n }\n const wake = () => {\n clearTimeout(timer);\n waiting.delete(wake);\n sendJson(response, { generation });\n };\n const timer = setTimeout(() => {\n waiting.delete(wake);\n response.writeHead(204).end();\n }, WAIT_MS);\n waiting.add(wake);\n response.on('close', () => {\n clearTimeout(timer);\n waiting.delete(wake);\n });\n };\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, address, () => resolve());\n });\n const { port: listening } = server.address() as AddressInfo;\n const origin = `http://${address}:${listening}`;\n if (developerKey) {\n const expires = Math.floor(Date.now() / 1000) + LINK_LIFETIME_SECONDS;\n const keyId = developerKey.keyId;\n const message = signedLinkMessage(origin, secret, expires, keyId);\n signature = { expires, keyId, sig: developerKey.sign(Buffer.from(message, 'utf8')) };\n }\n\n return {\n link: `${DEVICE_SCHEME}://connect?server=${encodeURIComponent(origin)}&secret=${secret}`,\n async publish(dir, { hot = false } = {}) {\n build = await readBuild(dir);\n error = null;\n announce();\n if (!hot) {\n hotSince = generation;\n }\n },\n fail(message) {\n error = message;\n announce();\n },\n close() {\n for (const wake of waiting) {\n wake();\n }\n return new Promise((resolve) => {\n server.close(() => resolve());\n server.closeAllConnections();\n });\n },\n };\n}\n\n// The first IPv4 address on a network other than this computer's own.\nfunction localNetworkAddress(): string | undefined {\n for (const addresses of Object.values(networkInterfaces())) {\n for (const candidate of addresses ?? []) {\n if (candidate.family === 'IPv4' && !candidate.internal) {\n return candidate.address;\n }\n }\n }\n return undefined;\n}\n\n// A copy of the build output, so a device downloading it never mixes two builds.\nasync function readBuild(dir: string): Promise<Build> {\n const files = new Map<string, { bytes: Buffer; hash: string }>();\n const entries = await readdir(dir, { recursive: true, withFileTypes: true });\n for (const entry of entries) {\n // Source maps stay on the computer, and archives are for `dotctl build`.\n if (!entry.isFile() || entry.name.endsWith('.map') || entry.name.endsWith('.zip')) {\n continue;\n }\n const path = join(entry.parentPath, entry.name);\n const bytes = await readFile(path);\n const hash = createHash('sha256').update(bytes).digest('base64url');\n files.set(relative(dir, path).split(sep).join('/'), { bytes, hash });\n }\n return { files };\n}\n\nfunction isAuthorized(request: IncomingMessage, token: string): boolean {\n const given = Buffer.from(request.headers.authorization ?? '');\n const expected = Buffer.from(`Bearer ${token}`);\n return given.length === expected.length && timingSafeEqual(given, expected);\n}\n\nfunction sendJson(response: ServerResponse, body: unknown): void {\n response.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(body));\n}\n\nasync function readText(request: IncomingMessage): Promise<string> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of request) {\n size += (chunk as Buffer).length;\n if (size > MAX_LOG_BYTES) {\n throw new Error('Too much log at once');\n }\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n","import { join } from 'node:path';\n\nimport type { Project } from '@monimesl/dot-compiler';\nimport { installedRuntime } from '@monimesl/dot-compiler';\nimport type { Simulator } from '@monimesl/dot-simulator';\nimport { startSimulator } from '@monimesl/dot-simulator';\n\n// `dev` and `preview` share .dot/files, so a preview finds what the dot saved while developing.\nexport function startDotSimulator(\n project: Project,\n outDir: string,\n port: number | undefined,\n): Promise<Simulator> {\n return startSimulator({\n dotDir: outDir,\n reactHostDir: installedRuntime(project.root).react.dir,\n name: project.dotJson.name,\n port,\n storageDir: join(project.root, '.dot', 'files'),\n });\n}\n","import { watch } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, loadProject, PAGES_DIR } from '@monimesl/dot-compiler';\nimport { renderUnicodeCompact } from 'uqr';\n\nimport { loadDeveloperKey, missingDeveloperKeyHint } from './device/developer-key';\nimport type { DeviceServer } from './device/server';\nimport { startDeviceServer } from './device/server';\nimport { describeError, printBuildTime, printWarnings } from './report';\nimport { startDotSimulator } from './simulator';\n\ninterface DevOptions extends BuildOptions {\n port?: number | undefined;\n // Also serves the dot to the example host apps on devices, through a link and a QR code.\n device?: boolean | undefined;\n}\n\n// Editors save a file in several writes; waiting this long turns them into one rebuild.\nconst CHANGE_DEBOUNCE_MS = 50;\n\nexport async function dev({ port, device, ...options }: DevOptions): Promise<() => Promise<void>> {\n const project = await loadProject(options.root);\n const outDir = resolve(project.root, options.outDir ?? 'dist');\n const buildOptions: BuildOptions = { mode: 'development', ...options, outDir };\n\n // Returns the error to show, with paths relative to the project.\n const buildApp = async (): Promise<string | null> => {\n const started = performance.now();\n try {\n printWarnings(await build(buildOptions));\n printBuildTime(started);\n return null;\n } catch (error) {\n const message = describeError(error).replaceAll(project.root + sep, '');\n console.error(`error: ${message}`);\n return message;\n }\n };\n\n const firstError = await buildApp();\n const simulator = await startDotSimulator(project, outDir, port);\n if (firstError) {\n simulator.error(firstError);\n }\n console.log(`\\n Simulator running at: ${simulator.url}\\n`);\n\n let devices: DeviceServer | undefined;\n if (device) {\n const developerKey = await loadDeveloperKey();\n devices = await startDeviceServer({\n developerKey,\n onConnect: (from) => console.log(`A device connected from ${from}`),\n onLog: (line) => console.log(`device ${line}`),\n });\n if (firstError) {\n devices.fail(firstError);\n } else {\n await devices.publish(outDir);\n }\n printDeviceLink(devices.link);\n if (developerKey) {\n console.log(` Signed with developer key ${developerKey.keyId}\\n`);\n } else {\n console.log(`${missingDeveloperKeyHint()}\\n`);\n }\n }\n\n // What changed since the last build that worked, to tell whether the new one can run in place.\n const changed = new Set<string>();\n const pagesDir = join(project.root, PAGES_DIR) + sep;\n const rebuilds = new RebuildQueue(async () => {\n // Changes that come in while it builds count toward the next build.\n const building = [...changed];\n const error = await buildApp();\n if (error) {\n simulator.error(error);\n devices?.fail(error);\n return;\n }\n for (const path of building) {\n changed.delete(path);\n }\n // Pages run again in place; anything else, such as dot.ts, .env or statics/, starts the dot\n // again on the pages it had open.\n const hot = building.every((path) => path.startsWith(pagesDir));\n if (hot) {\n simulator.hotReload();\n } else {\n simulator.reload();\n }\n await devices?.publish(outDir, { hot });\n });\n\n let debounceTimer: NodeJS.Timeout | undefined;\n const watcher = watch(project.root, { recursive: true }, (_event, file) => {\n if (!file || isIgnored(file)) {\n return;\n }\n const path = resolve(project.root, file);\n if (path === outDir || path.startsWith(outDir + sep)) {\n return;\n }\n changed.add(path);\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n console.log(`Changed ${relative(project.root, path)}`);\n rebuilds.request();\n }, CHANGE_DEBOUNCE_MS);\n });\n\n return async () => {\n clearTimeout(debounceTimer);\n watcher.close();\n await Promise.all([simulator.close(), devices?.close()]);\n };\n}\n\nfunction printDeviceLink(link: string): void {\n console.log(\n ' Scan this in Dash: turn on Enable Dot Debugging in Developer Settings, then tap Live Test on\\n' +\n ' the Dots tab.\\n',\n );\n console.log(renderUnicodeCompact(link, { border: 1 }).replace(/^/gm, ' '));\n console.log(`\\n ${link}\\n`);\n}\n\n// Runs one rebuild at a time; changes that arrive mid-build trigger exactly one more once it ends.\nclass RebuildQueue {\n readonly #rebuild: () => Promise<void>;\n #building = false;\n #changedWhileBuilding = false;\n\n constructor(rebuild: () => Promise<void>) {\n this.#rebuild = rebuild;\n }\n\n request(): void {\n if (this.#building) {\n this.#changedWhileBuilding = true;\n return;\n }\n void this.#build();\n }\n\n async #build(): Promise<void> {\n this.#building = true;\n this.#changedWhileBuilding = false;\n try {\n await this.#rebuild();\n } finally {\n this.#building = false;\n }\n if (this.#changedWhileBuilding) {\n this.request();\n }\n }\n}\n\n// Dependencies and hidden folders such as .git or .dot, but not .env files, which the build reads.\nfunction isIgnored(file: string): boolean {\n return file.split(/[\\\\/]/).some((segment) => {\n if (segment === '.env' || segment.startsWith('.env.')) {\n return false;\n }\n return segment === 'node_modules' || segment.startsWith('.');\n });\n}\n","import { resolve } from 'node:path';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, loadProject } from '@monimesl/dot-compiler';\nimport type { Simulator } from '@monimesl/dot-simulator';\n\nimport { printBuildTime, printWarnings } from './report';\nimport { startDotSimulator } from './simulator';\n\ninterface PreviewOptions extends BuildOptions {\n port?: number | undefined;\n}\n\n// Builds the dot as `dotctl build` does, and runs that build in the simulator: minified, with only\n// the components its pages use, as the host app gets it. It doesn't rebuild on change, since its\n// renderer has no components for a page to add.\nexport async function preview({ port, ...options }: PreviewOptions): Promise<Simulator> {\n const project = await loadProject(options.root);\n const outDir = resolve(project.root, options.outDir ?? 'dist');\n const started = performance.now();\n printWarnings(await build({ ...options, outDir, mode: 'production' }));\n printBuildTime(started);\n const simulator = await startDotSimulator(project, outDir, port);\n console.log(`\\n Simulator running at: ${simulator.url}\\n`);\n return simulator;\n}\n","import { emitKeypressEvents } from 'node:readline';\nimport { createInterface } from 'node:readline/promises';\nimport { styleText } from 'node:util';\n\nexport interface Choice<Value extends string> {\n value: Value;\n // Shown after the value, such as what a template has.\n hint?: string;\n}\n\ninterface Terminal {\n input: NodeJS.ReadStream;\n output: NodeJS.WriteStream;\n}\n\nconst TERMINAL: Terminal = { input: process.stdin, output: process.stdout };\n\nconst ERASE_BELOW = '\\x1b[0J';\nconst HIDE_CURSOR = '\\x1b[?25l';\nconst SHOW_CURSOR = '\\x1b[?25h';\nconst cursorUp = (lines: number) => `\\x1b[${lines}A`;\n\n// The person picks one of `choices` with the arrow keys and Enter. The list starts on `fallback`,\n// marked as the default, and it's `fallback` without a terminal to ask in.\nexport async function select<Value extends string>(\n question: string,\n choices: readonly Choice<Value>[],\n fallback: Value,\n { input, output }: Terminal = TERMINAL,\n): Promise<Value> {\n if (!input.isTTY) {\n return fallback;\n }\n let current = Math.max(\n 0,\n choices.findIndex((choice) => choice.value === fallback),\n );\n // Values are padded so their hints line up.\n const width = choices.some((choice) => choice.hint)\n ? Math.max(...choices.map((choice) => choice.value.length))\n : 0;\n const row = (choice: Choice<Value>, index: number) => {\n const name = choice.value.padEnd(width);\n const hint = choice.hint ? styleText('dim', ` ${choice.hint}`) : '';\n const defaultMark = choice.value === fallback ? styleText('green', ' (default)') : '';\n if (index === current) {\n return `${styleText('cyan', '❯')} ${styleText(['cyan', 'bold'], name)}${hint}${defaultMark}`;\n }\n return ` ${name}${hint}${defaultMark}`;\n };\n\n // Each drawing replaces the last: the question and its list, then the question and its answer.\n let drawnLines = 0;\n const draw = (lines: string[]) => {\n output.write(`${drawnLines ? cursorUp(drawnLines) : ''}${ERASE_BELOW}${lines.join('\\n')}\\n`);\n drawnLines = lines.length;\n };\n const drawList = () =>\n draw([\n `${styleText('bold', question)} ${styleText('dim', '↑/↓ to move, Enter to choose')}`,\n ...choices.map(row),\n ]);\n\n emitKeypressEvents(input);\n input.setRawMode(true);\n input.resume();\n output.write(HIDE_CURSOR);\n drawList();\n return new Promise((resolve) => {\n const onKeypress = (_text: string, key: { name?: string; ctrl?: boolean }) => {\n if (key.ctrl && key.name === 'c') {\n output.write(`${SHOW_CURSOR}\\n`);\n process.exit(130);\n }\n if (key.name === 'up' || key.name === 'k') {\n current = (current - 1 + choices.length) % choices.length;\n drawList();\n } else if (key.name === 'down' || key.name === 'j') {\n current = (current + 1) % choices.length;\n drawList();\n } else if (key.name === 'return' || key.name === 'enter') {\n const { value } = choices[current]!;\n input.off('keypress', onKeypress);\n input.setRawMode(false);\n input.pause();\n draw([`${styleText('bold', question)} ${styleText('cyan', value)}`]);\n output.write(SHOW_CURSOR);\n resolve(value);\n }\n };\n input.on('keypress', onKeypress);\n });\n}\n\n// A yes or no question, picked from a list like any other choice. Without a terminal, it's no.\nexport async function confirm(\n question: string,\n fallback: boolean,\n terminal: Terminal = TERMINAL,\n): Promise<boolean> {\n if (!terminal.input.isTTY) {\n return false;\n }\n const choices = [{ value: 'Yes' }, { value: 'No' }] as const;\n return (await select(question, choices, fallback ? 'Yes' : 'No', terminal)) === 'Yes';\n}\n\n// A typed answer; an empty one, or none without a terminal, is `fallback`, shown as the default.\nexport async function ask(\n question: string,\n fallback?: string,\n { input, output }: Terminal = TERMINAL,\n): Promise<string | undefined> {\n if (!input.isTTY) {\n return fallback;\n }\n const hint = fallback ? styleText('dim', ` (default: ${fallback})`) : '';\n const readline = createInterface({ input, output });\n try {\n const answer = await readline.question(`${styleText('bold', question)}${hint}: `);\n return answer.trim() || fallback;\n } catch (error) {\n // Ctrl+C or Ctrl+D\n if ((error as Error).name === 'AbortError') {\n return undefined;\n }\n throw error;\n } finally {\n readline.close();\n }\n}\n","import { spawn } from 'node:child_process';\nimport { relative } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build } from '@monimesl/dot-compiler';\nimport { DEFAULT_PORT } from '@monimesl/dot-simulator';\n\nimport { create, toDisplayName, toPackageName } from './create/create';\nimport { createPage } from './create/page';\nimport type { PackageManager } from './create/package-manager';\nimport type { Template } from './create/template';\nimport { isTemplate, TEMPLATE_HINTS, TEMPLATES } from './create/template';\nimport {\n installedManagers,\n isPackageManager,\n launchedBy,\n PACKAGE_MANAGERS,\n} from './create/package-manager';\nimport { dev } from './dev';\nimport { preview } from './preview';\nimport { ask, confirm, select } from './prompts';\nimport {\n defaultDeveloperKeyPath,\n loadDeveloperKey,\n missingDeveloperKeyHint,\n} from './device/developer-key';\nimport { describeError, printBuildTime, printWarnings } from './report';\n\nconst USAGE = `Usage:\n dotctl create [dir] [--name <name>] [--template <starter|showcase>]\n [--pm <npm|pnpm|yarn|bun>]\n Create a dot (asks for its name and template):\n starter is one page to build on, showcase a page\n for each feature\n dotctl create page <path> Add a page to the dot you are in: pages/<path>/ with\n view.dml, state.ts and controller.ts\n dotctl build [root] [options] Build the minified bundles the host app runs\n dotctl dev [root] [options] Run in the browser simulator, rebuilding on change\n dotctl preview [root] [options] Build as \\`build\\` does, and run that build in the browser\n simulator, as the host app gets it\n dotctl keys show Show the public key and key ID of this computer's\n developer key, which signs the links \\`dev --device\\`\n shows, for Dash to open\n dotctl lsp [--stdio] Serve .dml files to an editor over the Language Server\n Protocol, on stdin and stdout\n\nOptions:\n --out-dir <dir> Output directory (default: <root>/dist)\n --conditions <list> Extra export conditions, comma separated\n --port <port> Simulator port for \\`dev\\` and \\`preview\\`; the next free one is used\n if taken (default: ${DEFAULT_PORT})\n --device With \\`dev\\`, also serve the dot to the Dot example apps on phones on\n the local network, through a link and QR code; they reload on each build\n -h, --help Show this message`;\n\nasync function main(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n 'out-dir': { type: 'string' },\n conditions: { type: 'string' },\n port: { type: 'string' },\n device: { type: 'boolean' },\n name: { type: 'string' },\n template: { type: 'string' },\n pm: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n // Editors pass it to say the server talks over stdin and stdout, which is the only way it does.\n stdio: { type: 'boolean' },\n },\n });\n\n const [command, target, pagePath] = positionals;\n if (command === 'lsp' && !values.help) {\n // Loaded only here, so the other commands start without it.\n const { serveStdio } = await import('./lsp/server');\n serveStdio();\n // The connection exits the process when the editor says so.\n return new Promise<number>(() => {});\n }\n if (command === 'keys' && !values.help) {\n return keys(target);\n }\n if (command === 'create' && target === 'page' && !values.help) {\n return addPage(pagePath);\n }\n if (command === 'create' && !values.help) {\n return createApp(target, values.name, values.template, values.pm);\n }\n if (values.help || (command !== 'build' && command !== 'dev' && command !== 'preview')) {\n console.log(USAGE);\n return values.help ? 0 : 1;\n }\n const port = values.port === undefined ? undefined : Number(values.port);\n if (port !== undefined && !Number.isInteger(port)) {\n console.error(`Invalid --port \"${values.port}\"`);\n return 1;\n }\n\n const options: BuildOptions = { root: target ?? '.' };\n if (values['out-dir'] !== undefined) {\n options.outDir = values['out-dir'];\n }\n if (values.conditions !== undefined) {\n options.conditions = values.conditions.split(',');\n }\n\n if (command === 'dev') {\n const stop = await dev({ ...options, port, device: values.device });\n await new Promise((resolve) => process.once('SIGINT', resolve));\n await stop();\n return 0;\n }\n\n if (command === 'preview') {\n if (values.device) {\n console.error('--device works only with dotctl dev');\n return 1;\n }\n const simulator = await preview({ ...options, port });\n await new Promise((resolve) => process.once('SIGINT', resolve));\n await simulator.close();\n return 0;\n }\n\n const started = performance.now();\n const result = await build(options);\n for (const file of result.files.filter((file) => !file.endsWith('.map'))) {\n console.log(` ${relative(process.cwd(), file)}`);\n }\n printWarnings(result);\n printBuildTime(started);\n return 0;\n}\n\nasync function keys(action: string | undefined): Promise<number> {\n if (action !== 'show') {\n console.error('dotctl keys show');\n return 1;\n }\n const path = defaultDeveloperKeyPath();\n const key = await loadDeveloperKey(path);\n if (!key) {\n console.error(missingDeveloperKeyHint(path));\n return 1;\n }\n console.log(`\\n Public key: ${key.publicKey}\\n Key ID: ${key.keyId}\\n`);\n return 0;\n}\n\nasync function addPage(path: string | undefined): Promise<number> {\n if (path === undefined) {\n console.error(\n 'Which page? dotctl create page <path>, such as dotctl create page cart/checkout',\n );\n return 1;\n }\n if (path.startsWith('/')) {\n path = path.substring(1);\n }\n if (path.endsWith('/')) {\n path = path.substring(0, path.length - 1);\n }\n const { files, listing } = await createPage(path, process.cwd());\n for (const file of files) {\n console.log(` ${relative(process.cwd(), file)}`);\n }\n if (listing === 'added') {\n console.log(`\\nListed '${path}' in dot.ts.`);\n } else if (listing === 'manual') {\n console.log(`\\nList it in dot.ts to build it: defineDot({ pages: [..., '${path}'] })`);\n }\n return 0;\n}\n\nasync function createApp(\n dir: string | undefined,\n name: string | undefined,\n templateFlag: string | undefined,\n packageManagerFlag: string | undefined,\n): Promise<number> {\n if (templateFlag !== undefined && !isTemplate(templateFlag)) {\n console.error(`--template must be one of ${TEMPLATES.join(', ')}`);\n return 1;\n }\n if (packageManagerFlag !== undefined && !isPackageManager(packageManagerFlag)) {\n console.error(`--pm must be one of ${PACKAGE_MANAGERS.join(', ')}`);\n return 1;\n }\n name ??= await ask('Dot name', dir ? toDisplayName(dir) : 'Dot');\n if (!name) {\n console.error('A dot needs a name: dotctl create [dir] --name \"My Dot\"');\n return 1;\n }\n const template = templateFlag ?? (await chooseTemplate());\n const { root, workspace } = await create({\n name,\n dir: dir ?? toPackageName(name),\n template,\n });\n const path = relative(process.cwd(), root) || '.';\n console.log(`\\nCreated ${name} in ${path}`);\n if (workspace) {\n console.log('It is inside the Dot repository, so it uses the workspace packages.');\n }\n\n // A command cannot change its shell's directory, so it offers to carry on inside the new dot instead.\n let packageManager: PackageManager = workspace ? 'pnpm' : (packageManagerFlag ?? launchedBy());\n console.log();\n if (await confirm('Install and start it now?', true)) {\n if (!workspace && !packageManagerFlag) {\n packageManager = await choosePackageManager(packageManager);\n }\n const installed = await run(packageManager, ['install'], root);\n if (installed === 0) {\n return run(packageManager, ['run', 'dev'], root);\n }\n console.error(`\\n${packageManager} install failed.`);\n }\n console.log(\n `\\nNext:\\n\\n cd ${path}\\n ${packageManager} install\\n ${packageManager} run dev\\n`,\n );\n return 0;\n}\n\nfunction run(command: string, args: string[], cwd: string): Promise<number> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(command, args, {\n cwd,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n child.on('error', reject);\n child.on('exit', (code) => resolvePromise(code ?? 1));\n });\n}\n\nfunction chooseTemplate(): Promise<Template> {\n console.log();\n return select(\n 'Template?',\n TEMPLATES.map((template) => ({ value: template, hint: TEMPLATE_HINTS[template] })),\n 'starter',\n );\n}\n\nasync function choosePackageManager(suggested: PackageManager): Promise<PackageManager> {\n const installed = installedManagers();\n if (installed.length < 2) {\n return installed[0] ?? suggested;\n }\n const fallback = installed.includes(suggested) ? suggested : installed[0]!;\n return select(\n 'Package manager?',\n installed.map((manager) => ({ value: manager })),\n fallback,\n );\n}\n\nmain(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (error: unknown) => {\n console.error(`error: ${describeError(error)}`);\n process.exit(1);\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/report.ts","../src/utils.ts","../src/create/template.ts","../src/create/create.ts","../src/create/page.ts","../src/create/package-manager.ts","../src/device/developer-key.ts","../src/device/server.ts","../src/simulator.ts","../src/dev.ts","../src/preview.ts","../src/prompts.ts","../src/cli.ts"],"sourcesContent":["import { relative } from 'node:path';\n\nimport { DmlParseError } from '@monimesl/dot-dml-parser';\nimport type { BuildResult } from '@monimesl/dot-compiler';\nimport { CompileError } from '@monimesl/dot-compiler';\nimport { ScriptParseError } from '@monimesl/dot-script-parser';\n\n// A mistake in how a command was used. Its message is enough, so no stack trace is shown.\nexport class CommandError extends Error {\n override readonly name = 'CommandError';\n}\n\nexport function describeError(error: unknown): string {\n const known =\n error instanceof CommandError ||\n error instanceof CompileError ||\n error instanceof DmlParseError ||\n error instanceof ScriptParseError;\n if (known) {\n return error.message;\n }\n if (isArgumentError(error)) {\n // Keep only the first sentence. Node goes on to explain `--`, which doesn't help here.\n const [firstSentence] = error.message.split('. ');\n return `${firstSentence}. See dotctl --help.`;\n }\n if (error instanceof Error) {\n return error.stack ?? error.message;\n }\n return String(error);\n}\n\n// Node's parseArgs throws these for an unknown flag or a missing value.\nfunction isArgumentError(error: unknown): error is Error {\n if (!(error instanceof Error) || !('code' in error)) {\n return false;\n }\n return typeof error.code === 'string' && error.code.startsWith('ERR_PARSE_ARGS');\n}\n\n// Prints each file relative to the current folder.\nexport function printFiles(files: readonly string[]): void {\n for (const file of files) {\n console.log(` ${relative(process.cwd(), file)}`);\n }\n}\n\nexport function printWarnings({ warnings }: BuildResult): void {\n for (const warning of warnings) {\n console.warn(`warning: ${warning.message}`);\n }\n}\n\nexport function printBuildTime(startedAt: number): void {\n console.log(`Built in ${Math.round(performance.now() - startedAt)}ms`);\n}\n\nexport function printSimulatorUrl(url: string): void {\n console.log(`\\n Simulator running at: ${url}\\n`);\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { DOT_JSON_FILE } from '@monimesl/dot-compiler';\n\n// The nearest folder that has a file named `fileName`, starting at `dir` and walking up.\nexport function findFolderWith(fileName: string, dir: string): string | undefined {\n let current = dir;\n while (true) {\n if (existsSync(join(current, fileName))) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n return undefined;\n }\n current = parent;\n }\n}\n\nexport function findDotRoot(dir: string): string | undefined {\n return findFolderWith(DOT_JSON_FILE, dir);\n}\n\n// Where `dev` and `preview` write the build: `--out-dir` if given, else dist/ in the dot.\nexport function resolveOutDir(root: string, outDir: string | undefined): string {\n return resolve(root, outDir ?? 'dist');\n}\n\nexport function isOneOf<Value extends string>(\n values: readonly Value[],\n name: string,\n): name is Value {\n return (values as readonly string[]).includes(name);\n}\n","import { DEFAULT_DASH_API_VERSION } from '@monimesl/dot-core';\n\nimport { isOneOf } from '../utils';\n\nexport const TEMPLATES = ['starter', 'showcase'] as const;\n\nexport type Template = (typeof TEMPLATES)[number];\n\n// Shown next to each template when `dotctl create` asks which one to use.\nexport const TEMPLATE_HINTS: Record<Template, string> = {\n starter: 'one page to build on',\n showcase: 'a page for each feature, to learn from',\n};\n\nexport function isTemplate(name: string): name is Template {\n return isOneOf(TEMPLATES, name);\n}\n\ninterface TemplateOptions {\n name: string;\n // The npm package name, such as `my-dot`.\n packageName: string;\n // The dot's own package name, a reverse domain name such as `com.mysalone.thing`.\n dotPackage: string;\n dotVersion: string;\n workspace: boolean;\n template: Template;\n}\n\nexport const PAGE_FILES: Readonly<Record<string, string>> = {\n 'view.dml': '<View>\\n\\t<Text>My new page</Text>\\n</View>\\n',\n 'state.ts': 'export default {};\\n',\n 'controller.ts': `import state from './state';\n\nexport default definePage({\n initialState: state,\n});\n`,\n};\n\n// The files `dotctl create` copies from the template's example. It generates the rest.\nexport const TEMPLATE_FILES = ['dot.ts', 'pages', 'statics', '.env'] as const;\n\n// Editors that follow `$schema` can check dot.json and complete its fields. unpkg serves the schema\n// from the runtime's latest release on npm, and picks up a new release within minutes.\nconst DOT_JSON_SCHEMA = 'https://unpkg.com/@monimesl/dot-runtime/dot.schema.json';\n\n// Stands in for the ID Monime gives the dot when it's registered.\nexport const UNREGISTERED_DOT_ID = '<monime-Internal-Id>';\n\n// The files `dotctl create` writes itself, by path.\nexport function generatedFiles(options: TemplateOptions): Record<string, string> {\n return {\n 'package.json': packageJson(options),\n 'tsconfig.json': tsconfig(options),\n '.gitignore': 'node_modules/\\ndist/\\n# Types generated by dotctl\\n.dot/\\n',\n 'dot.json': dotJson(options),\n 'README.md': readme(options),\n };\n}\n\nfunction packageJson({ packageName, dotVersion, workspace }: TemplateOptions): string {\n const conditions = workspace ? ' --conditions @monimesl/dot-source' : '';\n return formatJson({\n name: packageName,\n private: true,\n type: 'module',\n scripts: {\n dev: `dotctl dev${conditions}`,\n build: `dotctl build${conditions}`,\n preview: `dotctl preview${conditions}`,\n typecheck: 'tsc --noEmit',\n },\n dependencies: { '@monimesl/dot-runtime': dotVersion },\n devDependencies: { '@monimesl/dot-cli': dotVersion, typescript: '^5.9.3' },\n });\n}\n\nfunction tsconfig({ workspace }: TemplateOptions): string {\n const compilerOptions: Record<string, unknown> = {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['@monimesl/dot-runtime/globals'],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n verbatimModuleSyntax: true,\n };\n if (workspace) {\n compilerOptions.customConditions = ['@monimesl/dot-source'];\n }\n return formatJson({\n compilerOptions,\n include: ['dot.ts', 'pages', '.dot/pages.d.ts', '.dot/env.d.ts'],\n });\n}\n\nfunction dotJson({ name, dotPackage, template }: TemplateOptions): string {\n const dot: Record<string, unknown> = {\n id: UNREGISTERED_DOT_ID,\n $schema: DOT_JSON_SCHEMA,\n package: dotPackage,\n name,\n version: '0.1.0',\n };\n if (template === 'showcase') {\n // The dash.media, dash.storage.file, dash.contacts, dash.account and dash.payments pages ask for these.\n dot.permissions = {\n account: 'Show your name on your concert ticket',\n camera: \"Take a photo for your concert ticket, or scan a ticket's QR code\",\n photoLibrary: 'Choose a photo for your concert ticket',\n files: 'Attach your concert ticket',\n contacts: 'Choose a friend to send a ticket to',\n payments: 'Pay for concert tickets',\n };\n // The showcase's network page sends requests to these hosts.\n dot.network = { hosts: ['itunes.apple.com', '*.mzstatic.com', 'httpbin.org'] };\n }\n dot.dash = { minApiVersion: DEFAULT_DASH_API_VERSION };\n return formatJson(dot);\n}\n\nconst TEMPLATE_READMES: Readonly<Record<Template, string>> = {\n starter: `It starts with one page, \\`index\\`. It shows a greeting from \\`.env\\` and a counter you\ncan tap. Change it, and add pages as the dot grows. To see how each feature works, make a showcase\ndot with \\`npx dotctl create my-tour --template showcase\\`.`,\n showcase: `It starts as a showcase. The \\`index\\` page links to a page for each feature, in three\nfolders: \\`pages/basics/\\` for how a page works, \\`pages/components/\\` for what a view can show,\nand \\`pages/dash/\\` for the phone's features. Read a page to see how it works. Then delete the\npages you don't need, both from \\`pages/\\` and from \\`dot.ts\\`.`,\n};\n\nfunction readme({ name, template }: TemplateOptions): string {\n return `# ${name}\n\nA dot: a mini app that runs inside Dash.\n\n\\`\\`\\`sh\nnpm install\nnpm run dev # run it in the simulator; it reloads on every change\nnpm run build # build it for Dash\n\\`\\`\\`\n\n${TEMPLATE_READMES[template]}\n\n## Pages\n\nEach page is a folder under \\`pages/\\` with three files:\n\n- \\`view.dml\\`: what the page shows. It has one root \\`<View>\\`, with everything else inside it.\n- \\`state.ts\\`: the data the page starts with.\n- \\`controller.ts\\`: how the data changes.\n\n\\`npx dotctl create page <path>\\` adds a page, such as \\`cart/checkout\\`, with these three files. It\nalso lists the page in \\`dot.ts\\`. The dot opens on the first page in that list.\n\n## dot.json\n\n\\`dot.json\\` describes the dot to Dash. Its \\`package\\` is a reverse domain name you own, such as\n\\`com.mysalone.thing\\`. You can't change it after publishing. To publish, register the dot with\nMonime first, and replace its \\`id\\`, \\`${UNREGISTERED_DOT_ID}\\`, with the ID Monime gives you.\n\\`network.hosts\\` lists every host the dot sends requests to with \\`dash.network\\`. Requests to any\nother host fail. Your editor can complete the other fields from the schema the file points to.\n\n## Which Dash opens it\n\n\\`dash.minApiVersion\\` in \\`dot.json\\` is the Dash API version the dot needs, such as \\`1.0\\`. Dash\nopens the dot when it offers that version, or a newer minor of the same major. Each Dash call's docs\nsay which version it came in, after \\`@since\\`. To use a newer call and still open on older Dash,\nkeep \\`minApiVersion\\` and check \\`this.dash.supports('contacts.pickPhone')\\` before the call.\n\\`dotctl dev\\` warns when the dot makes a newer call without checking.\n\n## .env\n\n\\`.env\\` holds public configuration. Code in the dot reads each variable from \\`env\\`, such as\n\\`env.GREETING\\`. Every variable is built into the dot, so anyone who has the dot can read it.\nNever put a secret there. \\`.env.development\\` and \\`.env.production\\` override it for \\`dev\\` and\n\\`build\\`.\n`;\n}\n\n// The package name to suggest, such as `com.example.my-dot` for the npm package `my-dot`. The npm\n// name is already lowercase letters, digits and inner hyphens. A part of a host name can be at most\n// 63 characters, so it's cut there.\nexport function suggestedDotPackage(packageName: string): string {\n return `com.example.${packageName.slice(0, 63).replace(/-+$/, '')}`;\n}\n\nfunction formatJson(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { cp, mkdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join, resolve } from 'node:path';\n\nimport { isDotPackage } from '@monimesl/dot-compiler';\n\nimport { CommandError } from '../report';\nimport { findFolderWith } from '../utils';\nimport type { Template } from './template';\nimport { generatedFiles, suggestedDotPackage, TEMPLATE_FILES } from './template';\n\ninterface CreateOptions {\n name: string;\n dir: string;\n // A reverse domain name, such as `com.mysalone.thing`. Defaults to `com.example.<npm name>`.\n dotPackage?: string;\n template?: Template;\n}\n\ninterface CreateResult {\n readonly root: string;\n readonly workspace: boolean;\n}\n\ninterface PackageJson {\n name: string;\n version: string;\n}\n\nexport const DOT_PACKAGE_RULE = 'Use lowercase words joined by dots, such as com.mysalone.thing.';\n\nexport async function create({\n name,\n dir,\n dotPackage,\n template = 'starter',\n}: CreateOptions): Promise<CreateResult> {\n const root = resolve(dir);\n if (existsSync(root) && readdirSync(root).length > 0) {\n throw new CommandError(`${dir} already exists and is not empty. Choose another folder`);\n }\n const packageName = toPackageName(name);\n if (!packageName) {\n throw new CommandError(`The name \"${name}\" needs at least one letter or digit`);\n }\n dotPackage ??= suggestedDotPackage(packageName);\n if (!isDotPackage(dotPackage)) {\n throw new CommandError(`\"${dotPackage}\" isn't a package name. ${DOT_PACKAGE_RULE}`);\n }\n\n const workspace = isInDotWorkspace(root);\n const source = templateDir(template);\n await mkdir(root, { recursive: true });\n for (const path of TEMPLATE_FILES) {\n await cp(join(source, path), join(root, path), { recursive: true });\n }\n const generated = generatedFiles({\n name,\n packageName,\n dotPackage,\n dotVersion: workspace ? 'workspace:*' : `^${cliVersion()}`,\n workspace,\n template,\n });\n for (const [path, content] of Object.entries(generated)) {\n await writeFile(join(root, path), content);\n }\n return { root, workspace };\n}\n\nexport function toPackageName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nexport function toDisplayName(dir: string): string {\n return basename(resolve(dir))\n .split(/[-_\\s]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n// Whether the nearest pnpm workspace above `dir` is the Dot repository.\nexport function isInDotWorkspace(dir: string): boolean {\n const workspaceRoot = findFolderWith('pnpm-workspace.yaml', dirname(dir));\n if (workspaceRoot === undefined) {\n return false;\n }\n const runtimeManifest = join(workspaceRoot, 'packages/runtime/package.json');\n if (!existsSync(runtimeManifest)) {\n return false;\n }\n return readPackageJson(runtimeManifest).name === '@monimesl/dot-runtime';\n}\n\n// Inside the repository, templates come from examples/. The published CLI ships its own copy.\nfunction templateDir(template: Template): string {\n const example = join(cliRoot(), '../../examples', template);\n if (existsSync(example)) {\n return example;\n }\n return join(cliRoot(), 'dist/templates', template);\n}\n\nfunction cliVersion(): string {\n return readPackageJson(join(cliRoot(), 'package.json')).version;\n}\n\nfunction readPackageJson(path: string): PackageJson {\n return JSON.parse(readFileSync(path, 'utf8')) as PackageJson;\n}\n\nfunction cliRoot(): string {\n return dirname(createRequire(import.meta.url).resolve('@monimesl/dot-cli/package.json'));\n}\n","import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { DOT_FILE, PAGES_DIR } from '@monimesl/dot-compiler';\nimport { isPageId } from '@monimesl/dot-core';\nimport type { DotModuleIR } from '@monimesl/dot-script-parser';\nimport { parseDotModule } from '@monimesl/dot-script-parser';\n\nimport { CommandError } from '../report';\nimport { findDotRoot } from '../utils';\nimport { PAGE_FILES } from './template';\n\n// Whether the page is now in `defineDot({ pages })` in dot.ts. `manual` means dot.ts couldn't be\n// updated, so the developer must add the page by hand.\ntype PageListing = 'added' | 'already' | 'manual';\n\ninterface CreatePageResult {\n readonly dir: string;\n readonly files: readonly string[];\n readonly listing: PageListing;\n}\n\n// Adds a page folder under pages/ in the dot that contains `cwd`, and lists it last in dot.ts.\nexport async function createPage(path: string, cwd: string): Promise<CreatePageResult> {\n if (!isPageId(path)) {\n throw new CommandError(\n `\"${path}\" is not a page path. Use letters, digits, \"-\" and \"_\", with \"/\" between folders, such as \"cart/checkout\"`,\n );\n }\n const root = findDotRoot(resolve(cwd));\n if (root === undefined) {\n throw new CommandError(\n 'There is no dot.json in this folder or any folder above it. Run this command inside a dot',\n );\n }\n const dir = join(root, PAGES_DIR, path);\n if (existsSync(dir)) {\n throw new CommandError(`pages/${path} already exists. Choose another path`);\n }\n await mkdir(dir, { recursive: true });\n const files: string[] = [];\n for (const [name, content] of Object.entries(PAGE_FILES)) {\n const file = join(dir, name);\n await writeFile(file, content);\n files.push(file);\n }\n const listing = await addToDotPages(join(root, DOT_FILE), path);\n return { dir, files, listing };\n}\n\nasync function addToDotPages(dotFile: string, path: string): Promise<PageListing> {\n if (!existsSync(dotFile)) {\n return 'manual';\n }\n const source = await readFile(dotFile, 'utf8');\n let dot: DotModuleIR;\n try {\n dot = parseDotModule(source, dotFile);\n } catch {\n return 'manual';\n }\n if (dot.pages.includes(path)) {\n return 'already';\n }\n const updated = insertPage(source, dot.lastPage, path);\n if (!listsPage(updated, dotFile, path)) {\n return 'manual';\n }\n await writeFile(dotFile, updated);\n return 'added';\n}\n\n// Inserts `path` after the last page, matching the list's style: same quotes, and on its own line\n// if each page has one.\nfunction insertPage(source: string, lastPage: DotModuleIR['lastPage'], path: string): string {\n const quote = source[lastPage.start] === '\"' ? '\"' : \"'\";\n const page = `${quote}${path}${quote}`;\n const before = source.slice(0, lastPage.end);\n const after = source.slice(lastPage.end);\n\n const lineStart = source.lastIndexOf('\\n', lastPage.start - 1) + 1;\n const indent = source.slice(lineStart, lastPage.start);\n const lastPageHasOwnLine = /^\\s*$/.test(indent);\n if (!lastPageHasOwnLine) {\n return `${before}, ${page}${after}`;\n }\n const trailingComma = /^\\s*,/.exec(after);\n if (trailingComma) {\n const end = lastPage.end + trailingComma[0].length;\n return `${source.slice(0, end)}\\n${indent}${page},${source.slice(end)}`;\n }\n return `${before},\\n${indent}${page}${after}`;\n}\n\n// Whether `source`, the edited dot.ts, still parses and lists `path`.\nfunction listsPage(source: string, dotFile: string, path: string): boolean {\n try {\n return parseDotModule(source, dotFile).pages.includes(path);\n } catch {\n return false;\n }\n}\n","import { spawnSync } from 'node:child_process';\n\nimport { isOneOf } from '../utils';\n\nexport const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'] as const;\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\nexport function isPackageManager(name: string): name is PackageManager {\n return isOneOf(PACKAGE_MANAGERS, name);\n}\n\nexport function launchedBy(userAgent = process.env.npm_config_user_agent ?? ''): PackageManager {\n return PACKAGE_MANAGERS.find((name) => userAgent.startsWith(`${name}/`)) ?? 'npm';\n}\n\nexport function installedManagers(\n isInstalled: (name: PackageManager) => boolean = isOnPath,\n): PackageManager[] {\n return PACKAGE_MANAGERS.filter(isInstalled);\n}\n\nfunction isOnPath(name: PackageManager): boolean {\n const result = spawnSync(name, ['--version'], {\n stdio: 'ignore',\n shell: process.platform === 'win32',\n });\n return result.status === 0;\n}\n","import { createPrivateKey, createPublicKey, sign } from 'node:crypto';\nimport type { KeyObject } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\n// The Ed25519 key this computer signs dotdev links with. The developer adds its public key to their\n// Monime account. Before Dash opens a link, Monime checks its signature.\nexport interface DeveloperKey {\n // The raw 32-byte public key in base64. This is what the developer adds to their account.\n readonly publicKey: string;\n // The first 8 bytes of the public key in lowercase hex. A link names its key by this ID.\n readonly keyId: string;\n // Returns the signature in base64.\n sign(bytes: Buffer): string;\n}\n\nexport function defaultDeveloperKeyPath(): string {\n return process.env.DOT_DEVELOPER_KEY ?? join(homedir(), '.dot', 'developer-key.pem');\n}\n\n// Explains how to make a key. dotctl reads the key but never creates it.\nexport function missingDeveloperKeyHint(path = defaultDeveloperKeyPath()): string {\n return (\n ` There is no developer key at ${path}. Dash only opens signed links.\\n` +\n \" Make one with OpenSSL 3. macOS's built-in openssl can't, so first run brew install openssl:\\n\\n\" +\n ` mkdir -p ${dirname(path)} && openssl genpkey -algorithm ed25519 -out ${path}\\n\\n` +\n ' Then run `dotctl keys show` and add the public key it prints to your Monime account.'\n );\n}\n\n// Returns undefined when there is no key file yet.\nexport async function loadDeveloperKey(\n path = defaultDeveloperKeyPath(),\n): Promise<DeveloperKey | undefined> {\n let pem: string;\n try {\n pem = await readFile(path, 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return undefined;\n }\n throw error;\n }\n const privateKey = createPrivateKey(pem);\n if (privateKey.asymmetricKeyType !== 'ed25519') {\n throw new Error(\n `${path} is not an Ed25519 key. Make one with: openssl genpkey -algorithm ed25519 -out ${path}`,\n );\n }\n return toDeveloperKey(privateKey);\n}\n\nfunction toDeveloperKey(privateKey: KeyObject): DeveloperKey {\n const publicKeyJwk = createPublicKey(privateKey).export({ format: 'jwk' });\n const rawPublicKey = Buffer.from(publicKeyJwk.x!, 'base64url');\n return {\n publicKey: rawPublicKey.toString('base64'),\n keyId: rawPublicKey.subarray(0, 8).toString('hex'),\n sign: (bytes) => sign(null, bytes, privateKey).toString('base64'),\n };\n}\n","import { createHash, createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readdir, readFile } from 'node:fs/promises';\nimport type { IncomingMessage, Server, ServerResponse } from 'node:http';\nimport { createServer } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { networkInterfaces } from 'node:os';\nimport { join, relative, sep } from 'node:path';\n\nimport type { DeveloperKey } from './developer-key';\n\ninterface DeviceServerOptions {\n // The address devices reach the server on. Defaults to the computer's local network address.\n address?: string | undefined;\n // Defaults to any free port. The link tells devices which one.\n port?: number | undefined;\n // Called for each line a device sends, such as its dot's console output.\n onLog?: (line: string, from: string) => void;\n onConnect?: (from: string) => void;\n // Signs the link. Hosts such as Dash only open links signed by a known developer.\n developerKey?: DeveloperKey | undefined;\n}\n\n// Serves a dot's builds to the example host apps on phones, which reload on each new build.\nexport interface DeviceServer {\n // The link a device opens: `dotdev://connect?server=…&secret=…`. It is kept short so the QR\n // code stays small. A signed link's signature is served at `GET /dev/link` instead.\n readonly link: string;\n // Serves the build output in `dir` as the newest build. A `hot` build changed only pages, so\n // devices can reload it in place and keep each open page's state.\n publish(dir: string, options?: { hot?: boolean }): Promise<void>;\n // Tells devices the newest build failed. They keep running the last good one.\n fail(message: string): void;\n close(): Promise<void>;\n}\n\n// A signed link's signature, served at `GET /dev/link`. It isn't secret, so it stays out of the QR\n// code.\nexport interface LinkSignature {\n readonly expires: number;\n readonly keyId: string;\n // In base64.\n readonly sig: string;\n}\n\ninterface BuildFile {\n readonly bytes: Buffer;\n readonly hash: string;\n}\n\nconst DEVICE_SCHEME = 'dotdev';\nconst FILES_PATH = '/dev/files/';\n\n// A waiting request ends after this and the device asks again, before the network drops the idle\n// connection.\nconst WAIT_MS = 25_000;\nconst MAX_LOG_BYTES = 1024 * 1024;\n// How long a signed link works. A photo of an old QR code soon becomes useless.\nconst LINK_LIFETIME_SECONDS = 12 * 60 * 60;\n\nexport const BUILD_MAC_HEADER = 'dot-build-mac';\n\n// The text a signed link's `sig` signs, one field per line.\nexport function signedLinkMessage(\n server: string,\n secret: string,\n expires: number,\n keyId: string,\n): string {\n return ['dotdev-connect', server, secret, String(expires), keyId].join('\\n');\n}\n\n// The bearer token a device sends. It is derived from the link's secret, so the link doesn't need\n// to carry it. Someone who sees the token on the network learns nothing about the secret.\nexport function deviceToken(secret: string): string {\n return hmacWithSecret(secret, 'dotdev-token');\n}\n\n// The HMAC-SHA256 of a build listing, keyed with the link's secret. A device only accepts listings\n// from someone who has the link, and each file must match its hash in the listing.\nexport function buildMac(secret: string, body: string): string {\n return hmacWithSecret(secret, `dotdev-build\\n${body}`);\n}\n\nexport async function startDeviceServer({\n address = localNetworkAddress(),\n port = 0,\n onLog = () => {},\n onConnect = () => {},\n developerKey,\n}: DeviceServerOptions = {}): Promise<DeviceServer> {\n if (address === undefined) {\n throw new Error(\n \"This computer has no local network address, so devices can't reach it. Connect to a network and try again\",\n );\n }\n const deviceServer = new LocalDeviceServer(onLog, onConnect);\n await deviceServer.listen(port, address, developerKey);\n return deviceServer;\n}\n\nclass LocalDeviceServer implements DeviceServer {\n readonly #onLog: (line: string, from: string) => void;\n readonly #onConnect: (from: string) => void;\n // The secret never goes over the network. Only the link carries it.\n readonly #secret = randomBytes(16).toString('base64url');\n readonly #token = deviceToken(this.#secret);\n readonly #server: Server;\n readonly #waiting = new Set<() => void>();\n readonly #connected = new Set<string>();\n #link = '';\n #signature: LinkSignature | null = null;\n #files: ReadonlyMap<string, BuildFile> = new Map();\n #generation = 0;\n // The oldest generation from which only hot builds lead to the newest. A device on this\n // generation or a later one can hot reload to the newest build.\n #hotSince = 0;\n #error: string | null = null;\n\n constructor(onLog: (line: string, from: string) => void, onConnect: (from: string) => void) {\n this.#onLog = onLog;\n this.#onConnect = onConnect;\n this.#server = createServer((request, response) => {\n this.#handle(request, response);\n });\n }\n\n get link(): string {\n return this.#link;\n }\n\n async listen(\n port: number,\n address: string,\n developerKey: DeveloperKey | undefined,\n ): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.#server.once('error', reject);\n this.#server.listen(port, address, () => resolve());\n });\n const { port: listeningPort } = this.#server.address() as AddressInfo;\n const origin = `http://${address}:${listeningPort}`;\n if (developerKey) {\n const expires = Math.floor(Date.now() / 1000) + LINK_LIFETIME_SECONDS;\n const keyId = developerKey.keyId;\n const message = signedLinkMessage(origin, this.#secret, expires, keyId);\n const sig = developerKey.sign(Buffer.from(message, 'utf8'));\n this.#signature = { expires, keyId, sig };\n }\n const server = encodeURIComponent(origin);\n this.#link = `${DEVICE_SCHEME}://connect?server=${server}&secret=${this.#secret}`;\n }\n\n async publish(dir: string, { hot = false }: { hot?: boolean } = {}): Promise<void> {\n this.#files = await readBuild(dir);\n this.#error = null;\n this.#announce();\n if (!hot) {\n this.#hotSince = this.#generation;\n }\n }\n\n fail(message: string): void {\n this.#error = message;\n this.#announce();\n }\n\n close(): Promise<void> {\n this.#wakeWaitingDevices();\n return new Promise((resolve) => {\n this.#server.close(() => resolve());\n this.#server.closeAllConnections();\n });\n }\n\n #announce(): void {\n this.#generation += 1;\n this.#wakeWaitingDevices();\n }\n\n #wakeWaitingDevices(): void {\n for (const wake of this.#waiting) {\n wake();\n }\n }\n\n #handle(request: IncomingMessage, response: ServerResponse): void {\n const from = request.socket.remoteAddress ?? 'a device';\n // Served without the token check: a device needs the signature to check the link before using\n // it, and the signature isn't secret.\n if (request.method === 'GET' && request.url === '/dev/link') {\n this.#sendSignature(response);\n return;\n }\n if (!isAuthorized(request, this.#token)) {\n response.writeHead(401).end();\n return;\n }\n const url = new URL(request.url ?? '/', 'http://device');\n const path = url.pathname;\n if (request.method === 'GET' && path === '/dev/build') {\n this.#sendBuild(response, from);\n } else if (request.method === 'GET' && path.startsWith(FILES_PATH)) {\n this.#sendFile(response, path, url.searchParams.get('generation'));\n } else if (request.method === 'GET' && path === '/dev/changes') {\n this.#waitForChange(response, Number(url.searchParams.get('after')));\n } else if (request.method === 'POST' && path === '/dev/log') {\n this.#receiveLog(request, response, from);\n } else {\n response.writeHead(404).end();\n }\n }\n\n #sendSignature(response: ServerResponse): void {\n if (this.#signature) {\n sendJson(response, this.#signature);\n } else {\n response.writeHead(404).end();\n }\n }\n\n #sendBuild(response: ServerResponse, from: string): void {\n if (!this.#connected.has(from)) {\n this.#connected.add(from);\n this.#onConnect(from);\n }\n const hashes: Record<string, string> = {};\n for (const [name, file] of this.#files) {\n hashes[name] = file.hash;\n }\n const body = JSON.stringify({\n generation: this.#generation,\n hotSince: this.#hotSince,\n files: hashes,\n error: this.#error,\n });\n response\n .writeHead(200, {\n 'content-type': 'application/json',\n [BUILD_MAC_HEADER]: buildMac(this.#secret, body),\n })\n .end(body);\n }\n\n #sendFile(response: ServerResponse, path: string, generation: string | null): void {\n // A file from an older build is refused, so a device never mixes two builds.\n if (generation !== String(this.#generation)) {\n response.writeHead(409).end();\n return;\n }\n const fileName = buildFileName(path);\n if (fileName === undefined) {\n response.writeHead(400).end();\n return;\n }\n const file = this.#files.get(fileName);\n if (!file) {\n response.writeHead(404).end();\n return;\n }\n response.writeHead(200, { 'content-type': 'application/octet-stream' }).end(file.bytes);\n }\n\n // Answers once there is a build newer than `after`, or with no content after WAIT_MS.\n #waitForChange(response: ServerResponse, after: number): void {\n if (this.#generation > after) {\n sendJson(response, { generation: this.#generation });\n return;\n }\n const stopWaiting = (): void => {\n clearTimeout(timer);\n this.#waiting.delete(wake);\n };\n const wake = (): void => {\n stopWaiting();\n sendJson(response, { generation: this.#generation });\n };\n const timer = setTimeout(() => {\n stopWaiting();\n response.writeHead(204).end();\n }, WAIT_MS);\n this.#waiting.add(wake);\n response.on('close', stopWaiting);\n }\n\n #receiveLog(request: IncomingMessage, response: ServerResponse, from: string): void {\n readLogText(request)\n .then((text) => {\n for (const line of text.split('\\n')) {\n this.#onLog(withoutControlCharacters(line), from);\n }\n response.writeHead(204).end();\n })\n .catch(() => response.writeHead(413).end());\n }\n}\n\nfunction hmacWithSecret(secret: string, text: string): string {\n const key = Buffer.from(secret, 'base64url');\n return createHmac('sha256', key).update(text, 'utf8').digest('base64url');\n}\n\n// The first IPv4 address that isn't a loopback address.\nfunction localNetworkAddress(): string | undefined {\n for (const addresses of Object.values(networkInterfaces())) {\n for (const candidate of addresses ?? []) {\n if (candidate.family === 'IPv4' && !candidate.internal) {\n return candidate.address;\n }\n }\n }\n return undefined;\n}\n\n// Reads the build output into memory, so a device downloading it never gets files from two builds.\nasync function readBuild(dir: string): Promise<Map<string, BuildFile>> {\n const files = new Map<string, BuildFile>();\n const entries = await readdir(dir, { recursive: true, withFileTypes: true });\n for (const entry of entries) {\n // Devices don't need source maps or the archives `dotctl build` writes.\n if (!entry.isFile() || entry.name.endsWith('.map') || entry.name.endsWith('.zip')) {\n continue;\n }\n const path = join(entry.parentPath, entry.name);\n const bytes = await readFile(path);\n const hash = createHash('sha256').update(bytes).digest('base64url');\n const name = relative(dir, path).split(sep).join('/');\n files.set(name, { bytes, hash });\n }\n return files;\n}\n\n// `/dev/files/ui/dot.js` asks for `ui/dot.js`. Each part of the name is URL-encoded, and a badly\n// encoded part, such as a lone `%`, gives undefined.\nfunction buildFileName(path: string): string | undefined {\n const encodedParts = path.slice(FILES_PATH.length).split('/');\n try {\n return encodedParts.map((part) => decodeURIComponent(part)).join('/');\n } catch {\n return undefined;\n }\n}\n\nfunction isAuthorized(request: IncomingMessage, token: string): boolean {\n const given = Buffer.from(request.headers.authorization ?? '');\n const expected = Buffer.from(`Bearer ${token}`);\n // timingSafeEqual throws on buffers of different lengths.\n if (given.length !== expected.length) {\n return false;\n }\n return timingSafeEqual(given, expected);\n}\n\nfunction sendJson(response: ServerResponse, body: unknown): void {\n response.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(body));\n}\n\n// A dot's console.log reaches the terminal, so it must not carry ANSI or OSC escape codes.\nfunction withoutControlCharacters(line: string): string {\n // eslint-disable-next-line no-control-regex\n return line.replace(/[\\u0000-\\u0008\\u000a-\\u001f\\u007f-\\u009f]/g, '');\n}\n\nasync function readLogText(request: IncomingMessage): Promise<string> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of request) {\n const bytes = chunk as Buffer;\n size += bytes.length;\n if (size > MAX_LOG_BYTES) {\n throw new Error(`A device sent more than ${MAX_LOG_BYTES} bytes of log at once`);\n }\n chunks.push(bytes);\n }\n return Buffer.concat(chunks).toString('utf8');\n}\n","import { join } from 'node:path';\n\nimport type { Project } from '@monimesl/dot-compiler';\nimport { installedRuntime } from '@monimesl/dot-compiler';\nimport type { Simulator } from '@monimesl/dot-simulator';\nimport { startSimulator } from '@monimesl/dot-simulator';\n\n// `dev` and `preview` share .dot/files, so a preview sees the files the dot saved during `dev`.\nexport function startDotSimulator(\n project: Project,\n outDir: string,\n port: number | undefined,\n): Promise<Simulator> {\n return startSimulator({\n dotDir: outDir,\n reactHostDir: installedRuntime(project.root).react.dir,\n name: project.dotJson.name,\n port,\n storageDir: join(project.root, '.dot', 'files'),\n });\n}\n","import { watch } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, loadProject, PAGES_DIR } from '@monimesl/dot-compiler';\nimport { renderUnicodeCompact } from 'uqr';\n\nimport { loadDeveloperKey, missingDeveloperKeyHint } from './device/developer-key';\nimport type { DeviceServer } from './device/server';\nimport { startDeviceServer } from './device/server';\nimport { describeError, printBuildTime, printSimulatorUrl, printWarnings } from './report';\nimport { startDotSimulator } from './simulator';\nimport { resolveOutDir } from './utils';\n\ninterface DevOptions extends BuildOptions {\n port?: number | undefined;\n // Also serve the dot to the example host apps on phones, through a link and a QR code.\n device?: boolean | undefined;\n}\n\n// Editors often save a file in several writes. Waiting this long turns them into one rebuild.\nconst CHANGE_DEBOUNCE_MS = 50;\n\n// Builds, serves and watches the dot. Returns a function that stops it all.\nexport async function dev({ port, device, ...options }: DevOptions): Promise<() => Promise<void>> {\n const project = await loadProject(options.root);\n const outDir = resolveOutDir(project.root, options.outDir);\n const buildOptions: BuildOptions = { mode: 'development', ...options, outDir };\n\n const firstError = await buildDot(buildOptions, project.root);\n const simulator = await startDotSimulator(project, outDir, port);\n if (firstError) {\n simulator.error(firstError);\n }\n printSimulatorUrl(simulator.url);\n\n let deviceServer: DeviceServer | undefined;\n if (device) {\n deviceServer = await startDevices(outDir, firstError);\n }\n\n // Files changed since the last good build. They decide whether the next build can hot reload.\n const changedFiles = new Set<string>();\n const pagesDir = join(project.root, PAGES_DIR) + sep;\n const rebuilds = new RebuildQueue(async () => {\n // Files that change during this build stay in `changedFiles` for the next one.\n const filesInThisBuild = [...changedFiles];\n const error = await buildDot(buildOptions, project.root);\n if (error) {\n simulator.error(error);\n deviceServer?.fail(error);\n return;\n }\n for (const path of filesInThisBuild) {\n changedFiles.delete(path);\n }\n // Page changes hot reload in place. Any other change, such as dot.ts, .env or statics/,\n // restarts the dot on the pages it had open.\n const hot = filesInThisBuild.every((path) => path.startsWith(pagesDir));\n if (hot) {\n simulator.hotReload();\n } else {\n simulator.reload();\n }\n await deviceServer?.publish(outDir, { hot });\n });\n\n let debounceTimer: NodeJS.Timeout | undefined;\n const watcher = watch(project.root, { recursive: true }, (_event, file) => {\n if (!file || isIgnored(file)) {\n return;\n }\n const path = resolve(project.root, file);\n if (path === outDir || path.startsWith(outDir + sep)) {\n return;\n }\n changedFiles.add(path);\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n console.log(`Changed ${relative(project.root, path)}`);\n rebuilds.request();\n }, CHANGE_DEBOUNCE_MS);\n });\n\n return async () => {\n clearTimeout(debounceTimer);\n watcher.close();\n await Promise.all([simulator.close(), deviceServer?.close()]);\n };\n}\n\n// Returns the error to show, with paths relative to the dot, or null if the build worked.\nasync function buildDot(buildOptions: BuildOptions, root: string): Promise<string | null> {\n const startedAt = performance.now();\n try {\n printWarnings(await build(buildOptions));\n printBuildTime(startedAt);\n return null;\n } catch (error) {\n const message = describeError(error).replaceAll(root + sep, '');\n console.error(`error: ${message}`);\n return message;\n }\n}\n\nasync function startDevices(outDir: string, firstError: string | null): Promise<DeviceServer> {\n const developerKey = await loadDeveloperKey();\n const deviceServer = await startDeviceServer({\n developerKey,\n onConnect: (from) => console.log(`A device connected from ${from}`),\n onLog: (line) => console.log(`device ${line}`),\n });\n if (firstError) {\n deviceServer.fail(firstError);\n } else {\n await deviceServer.publish(outDir);\n }\n printDeviceLink(deviceServer.link);\n if (developerKey) {\n console.log(` Signed with developer key ${developerKey.keyId}\\n`);\n } else {\n console.log(`${missingDeveloperKeyHint()}\\n`);\n }\n return deviceServer;\n}\n\nfunction printDeviceLink(link: string): void {\n console.log(\n ' To open it in Dash, turn on Enable Dot Debugging in Developer Settings.\\n' +\n ' Then tap Live Test on the Dots tab and scan this code.\\n',\n );\n const qrCode = renderUnicodeCompact(link, { border: 1 });\n console.log(qrCode.replace(/^/gm, ' '));\n console.log(`\\n ${link}\\n`);\n}\n\n// Runs one rebuild at a time. Changes during a build lead to exactly one more build after it.\nclass RebuildQueue {\n readonly #rebuild: () => Promise<void>;\n #building = false;\n #changedWhileBuilding = false;\n\n constructor(rebuild: () => Promise<void>) {\n this.#rebuild = rebuild;\n }\n\n request(): void {\n if (this.#building) {\n this.#changedWhileBuilding = true;\n return;\n }\n void this.#build();\n }\n\n async #build(): Promise<void> {\n this.#building = true;\n this.#changedWhileBuilding = false;\n try {\n await this.#rebuild();\n } finally {\n this.#building = false;\n }\n if (this.#changedWhileBuilding) {\n this.request();\n }\n }\n}\n\n// Skips node_modules and hidden folders such as .git or .dot, but not .env files: the build reads\n// them.\nfunction isIgnored(file: string): boolean {\n const segments = file.split(/[\\\\/]/);\n return segments.some((segment) => {\n if (segment === '.env' || segment.startsWith('.env.')) {\n return false;\n }\n return segment === 'node_modules' || segment.startsWith('.');\n });\n}\n","import type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, loadProject } from '@monimesl/dot-compiler';\nimport type { Simulator } from '@monimesl/dot-simulator';\n\nimport { printBuildTime, printSimulatorUrl, printWarnings } from './report';\nimport { startDotSimulator } from './simulator';\nimport { resolveOutDir } from './utils';\n\ninterface PreviewOptions extends BuildOptions {\n port?: number | undefined;\n}\n\n// Runs the `dotctl build` output in the simulator: minified, with only the components its pages\n// use. It doesn't rebuild on change, because a new component in a page wouldn't be in the build.\nexport async function preview({ port, ...options }: PreviewOptions): Promise<Simulator> {\n const project = await loadProject(options.root);\n const outDir = resolveOutDir(project.root, options.outDir);\n const startedAt = performance.now();\n const result = await build({ ...options, outDir, mode: 'production' });\n printWarnings(result);\n printBuildTime(startedAt);\n const simulator = await startDotSimulator(project, outDir, port);\n printSimulatorUrl(simulator.url);\n return simulator;\n}\n","import { emitKeypressEvents } from 'node:readline';\nimport { createInterface } from 'node:readline/promises';\nimport { styleText } from 'node:util';\n\nexport interface Choice<Value extends string> {\n value: Value;\n // Shown dimmed after the value, such as a short description of a template.\n hint?: string;\n}\n\ninterface Terminal {\n input: NodeJS.ReadStream;\n output: NodeJS.WriteStream;\n}\n\ninterface Keypress {\n name?: string;\n ctrl?: boolean;\n}\n\nconst TERMINAL: Terminal = { input: process.stdin, output: process.stdout };\n\nconst ERASE_BELOW = '\\x1b[0J';\nconst HIDE_CURSOR = '\\x1b[?25l';\nconst SHOW_CURSOR = '\\x1b[?25h';\n\n// Lets the person pick one of `choices` with the arrow keys and Enter. The list starts on\n// `fallback`, marked as the default. Without a terminal, it returns `fallback` without asking.\nexport async function select<Value extends string>(\n question: string,\n choices: readonly Choice<Value>[],\n fallback: Value,\n { input, output }: Terminal = TERMINAL,\n): Promise<Value> {\n if (!input.isTTY) {\n return fallback;\n }\n let selectedIndex = choices.findIndex((choice) => choice.value === fallback);\n if (selectedIndex < 0) {\n selectedIndex = 0;\n }\n // Pad the values so their hints line up.\n let valueWidth = 0;\n if (choices.some((choice) => choice.hint)) {\n valueWidth = Math.max(...choices.map((choice) => choice.value.length));\n }\n const formatChoice = (choice: Choice<Value>, index: number): string => {\n const value = choice.value.padEnd(valueWidth);\n const hint = choice.hint ? styleText('dim', ` ${choice.hint}`) : '';\n const defaultMark = choice.value === fallback ? styleText('green', ' (default)') : '';\n if (index === selectedIndex) {\n const pointer = styleText('cyan', '❯');\n return `${pointer} ${styleText(['cyan', 'bold'], value)}${hint}${defaultMark}`;\n }\n return ` ${value}${hint}${defaultMark}`;\n };\n\n // Each draw replaces the one before. First the question and its list, then the question and the\n // answer.\n let drawnLines = 0;\n const draw = (lines: string[]): void => {\n let moveUp = '';\n if (drawnLines > 0) {\n moveUp = cursorUp(drawnLines);\n }\n output.write(`${moveUp}${ERASE_BELOW}${lines.join('\\n')}\\n`);\n drawnLines = lines.length;\n };\n const drawQuestionAndChoices = (): void => {\n const keysHint = styleText('dim', '↑/↓ to move, Enter to choose');\n draw([`${styleText('bold', question)} ${keysHint}`, ...choices.map(formatChoice)]);\n };\n\n emitKeypressEvents(input);\n input.setRawMode(true);\n input.resume();\n output.write(HIDE_CURSOR);\n drawQuestionAndChoices();\n return new Promise((resolve) => {\n const onKeypress = (_text: string, key: Keypress): void => {\n if (key.ctrl && key.name === 'c') {\n output.write(`${SHOW_CURSOR}\\n`);\n process.exit(130);\n }\n if (key.name === 'up' || key.name === 'k') {\n selectedIndex = (selectedIndex - 1 + choices.length) % choices.length;\n drawQuestionAndChoices();\n } else if (key.name === 'down' || key.name === 'j') {\n selectedIndex = (selectedIndex + 1) % choices.length;\n drawQuestionAndChoices();\n } else if (key.name === 'return' || key.name === 'enter') {\n const { value } = choices[selectedIndex]!;\n input.off('keypress', onKeypress);\n input.setRawMode(false);\n input.pause();\n draw([`${styleText('bold', question)} ${styleText('cyan', value)}`]);\n output.write(SHOW_CURSOR);\n resolve(value);\n }\n };\n input.on('keypress', onKeypress);\n });\n}\n\n// A yes or no question, shown as a list. Without a terminal, the answer is always no.\nexport async function confirm(\n question: string,\n fallback: boolean,\n terminal: Terminal = TERMINAL,\n): Promise<boolean> {\n if (!terminal.input.isTTY) {\n return false;\n }\n const choices = [{ value: 'Yes' }, { value: 'No' }] as const;\n const answer = await select(question, choices, fallback ? 'Yes' : 'No', terminal);\n return answer === 'Yes';\n}\n\n// Asks for a typed answer, with an optional `hint` shown dimmed after the question. An empty answer,\n// or no terminal, gives `fallback`, shown as the default.\nexport async function ask(\n question: string,\n fallback?: string,\n hint?: string,\n { input, output }: Terminal = TERMINAL,\n): Promise<string | undefined> {\n if (!input.isTTY) {\n return fallback;\n }\n const hintText = hint ? styleText('dim', `, ${hint}`) : '';\n const defaultMark = fallback ? styleText('dim', ` (default: ${fallback})`) : '';\n const readline = createInterface({ input, output });\n try {\n const answer = await readline.question(\n `${styleText('bold', question)}${hintText}${defaultMark}: `,\n );\n const trimmedAnswer = answer.trim();\n if (trimmedAnswer === '') {\n return fallback;\n }\n return trimmedAnswer;\n } catch (error) {\n // The person pressed Ctrl+C or Ctrl+D.\n if ((error as Error).name === 'AbortError') {\n return undefined;\n }\n throw error;\n } finally {\n readline.close();\n }\n}\n\nfunction cursorUp(lines: number): string {\n return `\\x1b[${lines}A`;\n}\n","import { spawn } from 'node:child_process';\nimport { relative } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, isDotPackage } from '@monimesl/dot-compiler';\nimport { DEFAULT_PORT } from '@monimesl/dot-simulator';\n\nimport { create, DOT_PACKAGE_RULE, toDisplayName, toPackageName } from './create/create';\nimport { createPage } from './create/page';\nimport type { PackageManager } from './create/package-manager';\nimport {\n installedManagers,\n isPackageManager,\n launchedBy,\n PACKAGE_MANAGERS,\n} from './create/package-manager';\nimport type { Template } from './create/template';\nimport { isTemplate, suggestedDotPackage, TEMPLATE_HINTS, TEMPLATES } from './create/template';\nimport { dev } from './dev';\nimport {\n defaultDeveloperKeyPath,\n loadDeveloperKey,\n missingDeveloperKeyHint,\n} from './device/developer-key';\nimport { preview } from './preview';\nimport { ask, confirm, select } from './prompts';\nimport { describeError, printBuildTime, printFiles, printWarnings } from './report';\n\nconst USAGE = `Usage:\n dotctl create [dir] [--name <name>] [--package <com.mysalone.thing>]\n [--template <starter|showcase>] [--pm <npm|pnpm|yarn|bun>]\n Create a dot. Asks for its name, its package name\n (a reverse domain name you own) and its template:\n starter is one page to build on, showcase has a\n page for each feature\n dotctl create page <path> Add a page to the dot you are in. Writes\n pages/<path>/ with view.dml, state.ts and controller.ts\n dotctl build [root] [options] Build the minified bundles the host app runs\n dotctl dev [root] [options] Run the dot in the browser simulator and rebuild on\n every change\n dotctl preview [root] [options] Build as \\`build\\` does, then run that build in the\n browser simulator, exactly as the host app gets it\n dotctl keys show Show this computer's developer key: its public key\n and key ID. The key signs the links that\n \\`dev --device\\` shows, so Dash will open them\n dotctl lsp [--stdio] Start the .dml language server for editors. It talks\n over stdin and stdout\n\nOptions:\n --out-dir <dir> Output directory (default: <root>/dist)\n --conditions <list> Extra export conditions, separated by commas\n --port <port> Simulator port for \\`dev\\` and \\`preview\\`. If it is taken, the\n next free port is used (default: ${DEFAULT_PORT})\n --device With \\`dev\\`, also serve the dot to the Dot example apps on phones\n on your local network, through a link and QR code. The apps\n reload after each build\n -h, --help Show this message`;\n\n// The flags of `dotctl create`, as typed.\ninterface CreateFlags {\n readonly name: string | undefined;\n readonly dotPackage: string | undefined;\n readonly template: string | undefined;\n readonly packageManager: string | undefined;\n}\n\nasync function main(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n 'out-dir': { type: 'string' },\n conditions: { type: 'string' },\n port: { type: 'string' },\n device: { type: 'boolean' },\n name: { type: 'string' },\n package: { type: 'string' },\n template: { type: 'string' },\n pm: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n // Editors pass --stdio. The server always uses stdin and stdout, so the flag changes nothing.\n stdio: { type: 'boolean' },\n },\n });\n const [command, target, pagePath] = positionals;\n if (values.help) {\n console.log(USAGE);\n return 0;\n }\n\n switch (command) {\n case 'lsp':\n return serveLanguageServer();\n case 'keys':\n return showKeys(target);\n case 'create':\n if (target === 'page') {\n return addPage(pagePath);\n }\n return createDot(target, {\n name: values.name,\n dotPackage: values.package,\n template: values.template,\n packageManager: values.pm,\n });\n case 'build':\n case 'dev':\n case 'preview':\n break;\n default:\n console.log(USAGE);\n return 1;\n }\n\n let port: number | undefined;\n if (values.port !== undefined) {\n port = Number(values.port);\n if (!Number.isInteger(port)) {\n console.error(`--port must be a whole number, not \"${values.port}\"`);\n return 1;\n }\n }\n const options: BuildOptions = { root: target ?? '.' };\n if (values['out-dir'] !== undefined) {\n options.outDir = values['out-dir'];\n }\n if (values.conditions !== undefined) {\n options.conditions = values.conditions.split(',');\n }\n\n if (command === 'dev') {\n return runDev(options, port, values.device);\n }\n if (command === 'preview') {\n return runPreview(options, port, values.device);\n }\n return runBuild(options);\n}\n\nasync function serveLanguageServer(): Promise<number> {\n // Imported lazily so the other commands start faster.\n const { serveStdio } = await import('./lsp/server');\n serveStdio();\n // Never resolves: the connection exits the process when the editor asks it to.\n return new Promise<number>(() => {});\n}\n\nasync function runDev(\n options: BuildOptions,\n port: number | undefined,\n device: boolean | undefined,\n): Promise<number> {\n const stop = await dev({ ...options, port, device });\n await waitForCtrlC();\n await stop();\n return 0;\n}\n\nasync function runPreview(\n options: BuildOptions,\n port: number | undefined,\n device: boolean | undefined,\n): Promise<number> {\n if (device) {\n console.error('--device only works with dotctl dev');\n return 1;\n }\n const simulator = await preview({ ...options, port });\n await waitForCtrlC();\n await simulator.close();\n return 0;\n}\n\nasync function runBuild(options: BuildOptions): Promise<number> {\n const startedAt = performance.now();\n const result = await build(options);\n printFiles(result.files.filter((file) => !file.endsWith('.map')));\n printWarnings(result);\n printBuildTime(startedAt);\n return 0;\n}\n\nfunction waitForCtrlC(): Promise<void> {\n return new Promise((resolve) => {\n process.once('SIGINT', () => resolve());\n });\n}\n\nasync function showKeys(action: string | undefined): Promise<number> {\n if (action !== 'show') {\n console.error('Usage: dotctl keys show');\n return 1;\n }\n const path = defaultDeveloperKeyPath();\n const key = await loadDeveloperKey(path);\n if (!key) {\n console.error(missingDeveloperKeyHint(path));\n return 1;\n }\n console.log(`\\n Public key: ${key.publicKey}\\n Key ID: ${key.keyId}\\n`);\n return 0;\n}\n\nasync function addPage(typedPath: string | undefined): Promise<number> {\n if (typedPath === undefined) {\n console.error('Give the page a path, such as: dotctl create page cart/checkout');\n return 1;\n }\n const path = trimSlashes(typedPath);\n const { files, listing } = await createPage(path, process.cwd());\n printFiles(files);\n if (listing === 'added') {\n console.log(`\\nListed '${path}' in dot.ts.`);\n } else if (listing === 'manual') {\n console.log(\n `\\nAdd it to the pages in dot.ts so it gets built: defineDot({ pages: [..., '${path}'] })`,\n );\n }\n return 0;\n}\n\n// Removes one leading and one trailing slash, so `/cart/checkout/` is `cart/checkout`.\nfunction trimSlashes(path: string): string {\n let trimmed = path;\n if (trimmed.startsWith('/')) {\n trimmed = trimmed.substring(1);\n }\n if (trimmed.endsWith('/')) {\n trimmed = trimmed.substring(0, trimmed.length - 1);\n }\n return trimmed;\n}\n\nasync function createDot(dir: string | undefined, flags: CreateFlags): Promise<number> {\n const templateFlag = flags.template;\n if (templateFlag !== undefined && !isTemplate(templateFlag)) {\n console.error(`--template must be one of ${TEMPLATES.join(', ')}`);\n return 1;\n }\n const packageManagerFlag = flags.packageManager;\n if (packageManagerFlag !== undefined && !isPackageManager(packageManagerFlag)) {\n console.error(`--pm must be one of ${PACKAGE_MANAGERS.join(', ')}`);\n return 1;\n }\n let name = flags.name;\n if (name === undefined) {\n const suggestedName = dir ? toDisplayName(dir) : 'Dot';\n name = await ask('Dot name', suggestedName);\n }\n if (!name) {\n console.error('The dot needs a name. Pass one with: dotctl create [dir] --name \"My Dot\"');\n return 1;\n }\n const dotPackageFlag = flags.dotPackage;\n if (dotPackageFlag !== undefined && !isDotPackage(dotPackageFlag)) {\n console.error(`--package \"${dotPackageFlag}\" isn't a package name. ${DOT_PACKAGE_RULE}`);\n return 1;\n }\n let dotPackage = dotPackageFlag;\n if (dotPackage === undefined) {\n dotPackage = await askDotPackage(suggestedDotPackage(toPackageName(name)));\n }\n if (!dotPackage) {\n return 1;\n }\n let template = templateFlag;\n if (template === undefined) {\n template = await chooseTemplate();\n }\n\n const { root, workspace } = await create({\n name,\n dir: dir ?? toPackageName(name),\n dotPackage,\n template,\n });\n let path = relative(process.cwd(), root);\n if (path === '') {\n path = '.';\n }\n console.log(`\\nCreated ${name} in ${path}`);\n if (workspace) {\n console.log('It is inside the Dot repository, so it uses the workspace packages.');\n }\n\n // A command can't change its shell's folder, so it offers to install and start the dot from here.\n let packageManager: PackageManager;\n if (workspace) {\n packageManager = 'pnpm';\n } else {\n packageManager = packageManagerFlag ?? launchedBy();\n }\n console.log();\n if (await confirm('Install and start it now?', true)) {\n if (!workspace && !packageManagerFlag) {\n packageManager = await choosePackageManager(packageManager);\n }\n const installExitCode = await runCommand(packageManager, ['install'], root);\n if (installExitCode === 0) {\n return runCommand(packageManager, ['run', 'dev'], root);\n }\n console.error(\n `\\n${packageManager} install failed. Fix the problem above, then run the steps below.`,\n );\n }\n console.log(\n `\\nNext:\\n\\n cd ${path}\\n ${packageManager} install\\n ${packageManager} run dev\\n`,\n );\n return 0;\n}\n\n// Runs a command in `cwd`, showing its output, and returns its exit code.\nfunction runCommand(command: string, args: string[], cwd: string): Promise<number> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n stdio: 'inherit',\n shell: process.platform === 'win32',\n });\n child.on('error', reject);\n // A child killed by a signal has no exit code. Count that as a failure.\n child.on('exit', (exitCode) => resolve(exitCode ?? 1));\n });\n}\n\n// Asks again until the answer is a package name. Undefined when the person stops with Ctrl+C.\nasync function askDotPackage(suggested: string): Promise<string | undefined> {\n while (true) {\n const answer = await ask('Package name', suggested, 'a reverse domain name you own');\n if (answer === undefined || isDotPackage(answer)) {\n return answer;\n }\n console.error(`\"${answer}\" isn't a package name. ${DOT_PACKAGE_RULE}`);\n }\n}\n\nfunction chooseTemplate(): Promise<Template> {\n console.log();\n const choices = TEMPLATES.map((template) => ({\n value: template,\n hint: TEMPLATE_HINTS[template],\n }));\n return select('Template?', choices, 'starter');\n}\n\nasync function choosePackageManager(suggested: PackageManager): Promise<PackageManager> {\n const installed = installedManagers();\n if (installed.length < 2) {\n return installed[0] ?? suggested;\n }\n let fallback = installed[0]!;\n if (installed.includes(suggested)) {\n fallback = suggested;\n }\n const choices = installed.map((manager) => ({ value: manager }));\n return select('Package manager?', choices, fallback);\n}\n\nmain(process.argv.slice(2)).then(\n (exitCode) => process.exit(exitCode),\n (error: unknown) => {\n console.error(`error: ${describeError(error)}`);\n process.exit(1);\n },\n);\n"],"mappings":"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"}
|