@monimesl/dot-cli 0.1.0-alpha.2 → 0.1.0-alpha.4
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 +34 -15
- package/dist/cli.js +386 -57
- package/dist/cli.js.map +1 -1
- package/dist/server-DFOUQnLA.js +11263 -0
- package/dist/server-DFOUQnLA.js.map +1 -0
- package/dist/templates/showcase/.env +3 -0
- package/dist/templates/showcase/dot.ts +22 -0
- package/dist/templates/showcase/pages/carousel/controller.ts +10 -0
- package/dist/templates/showcase/pages/carousel/state.ts +40 -0
- package/dist/templates/showcase/pages/carousel/view.dml +37 -0
- package/dist/templates/showcase/pages/device/controller.ts +70 -0
- package/dist/templates/showcase/pages/device/state.ts +7 -0
- package/dist/templates/showcase/pages/device/view.dml +44 -0
- package/dist/templates/showcase/pages/feedback/controller.ts +16 -0
- package/dist/templates/showcase/pages/feedback/state.ts +7 -0
- package/dist/templates/showcase/pages/feedback/view.dml +87 -0
- package/dist/templates/showcase/pages/files/controller.ts +47 -0
- package/dist/templates/showcase/pages/files/state.ts +11 -0
- package/dist/templates/showcase/pages/files/view.dml +35 -0
- package/dist/templates/showcase/pages/filters/controller.ts +28 -0
- package/dist/templates/showcase/pages/filters/state.ts +72 -0
- package/dist/templates/showcase/pages/filters/view.dml +43 -0
- package/dist/templates/showcase/pages/forms/controller.ts +44 -0
- package/dist/templates/showcase/pages/forms/state.ts +15 -0
- package/dist/templates/showcase/pages/forms/view.dml +39 -0
- package/dist/templates/showcase/pages/images/controller.ts +15 -0
- package/dist/templates/showcase/pages/images/state.ts +7 -0
- package/dist/templates/showcase/pages/images/view.dml +38 -0
- package/dist/templates/showcase/pages/index/controller.ts +10 -0
- package/dist/templates/showcase/pages/index/state.ts +116 -0
- package/dist/templates/showcase/pages/index/view.dml +20 -0
- package/dist/templates/showcase/pages/layout/controller.ts +26 -0
- package/dist/templates/showcase/pages/layout/state.ts +14 -0
- package/dist/templates/showcase/pages/layout/view.dml +80 -0
- package/dist/templates/showcase/pages/lists/controller.ts +36 -0
- package/dist/templates/showcase/pages/lists/state.ts +96 -0
- package/dist/templates/showcase/pages/lists/view.dml +59 -0
- package/dist/templates/showcase/pages/navigation/controller.ts +64 -0
- package/dist/templates/showcase/pages/navigation/state.ts +17 -0
- package/dist/templates/showcase/pages/navigation/view.dml +34 -0
- package/dist/templates/showcase/pages/network/controller.ts +107 -0
- package/dist/templates/showcase/pages/network/state.ts +15 -0
- package/dist/templates/showcase/pages/network/view.dml +56 -0
- package/dist/templates/showcase/pages/payments/controller.ts +42 -0
- package/dist/templates/showcase/pages/payments/state.ts +10 -0
- package/dist/templates/showcase/pages/payments/view.dml +35 -0
- package/dist/templates/showcase/pages/state/controller.ts +22 -0
- package/dist/templates/showcase/pages/state/state.ts +10 -0
- package/dist/templates/showcase/pages/state/view.dml +33 -0
- package/dist/templates/showcase/pages/text/controller.ts +10 -0
- package/dist/templates/showcase/pages/text/state.ts +7 -0
- package/dist/templates/showcase/pages/text/view.dml +49 -0
- package/dist/templates/starter/.env +3 -0
- package/dist/templates/starter/dot.ts +3 -0
- package/dist/templates/starter/pages/index/controller.ts +9 -0
- package/dist/templates/starter/pages/index/state.ts +4 -0
- package/dist/templates/starter/pages/index/view.dml +16 -0
- package/dist/templates/starter/statics/logo.png +0 -0
- package/package.json +12 -7
- package/dist/template/.env +0 -3
- package/dist/template/dot.ts +0 -6
- package/dist/template/pages/help/tips/controller.ts +0 -30
- package/dist/template/pages/help/tips/state.ts +0 -11
- package/dist/template/pages/help/tips/view.dml +0 -15
- package/dist/template/pages/index/controller.ts +0 -67
- package/dist/template/pages/index/state.ts +0 -17
- package/dist/template/pages/index/view.dml +0 -66
- /package/dist/{template → templates/showcase}/statics/logo.png +0 -0
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/create/template.ts","../src/create/create.ts","../src/create/package-manager.ts","../src/report.ts","../src/dev.ts","../src/cli.ts"],"sourcesContent":["export interface TemplateOptions {\n name: string;\n packageName: string;\n dotVersion: string;\n workspace: boolean;\n}\n\n// The dot itself is copied from the counter example; these are the files around it.\nexport const TEMPLATE_FILES = ['dot.ts', 'pages', 'statics', '.env'] as const;\n\n// Editors that follow `$schema` 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': json({\n $schema: DOT_JSON_SCHEMA,\n id: `com.example.${idWord(options.packageName)}`,\n name: options.name,\n version: '0.1.0',\n }),\n 'README.md': readme(options.name),\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 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 readme(name: string): 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). List new pages in\n\\`dot.ts\\`; the first one 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. Your editor completes the other fields\nfrom the schema it points to.\n\n\\`.env\\` holds public configuration: variables named \\`DOT_PUBLIC_…\\`, which the service reads as\n\\`env.DOT_PUBLIC_…\\`. They are built into the dot, so anyone who has it can read them: never put a\nsecret there. \\`.env.development\\` and \\`.env.production\\` override it for \\`dev\\` and \\`build\\`.\n\nIt starts as a counter with two pages. \\`index\\` counts taps with mutations. \\`help/tips\\` shows\nnavigation: each page you open goes on top of the stack, Back returns to the one below, and the\ntrail at the top shows where you are.\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 { projectFiles, TEMPLATE_FILES } from './template';\n\nexport interface CreateOptions {\n name: string;\n dir: string;\n}\n\nexport interface 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({ name, dir }: CreateOptions): Promise<CreateResult> {\n const root = resolve(dir);\n if (existsSync(root) && readdirSync(root).length > 0) {\n throw new Error(`${dir} already exists and is not empty`);\n }\n const packageName = toPackageName(name);\n if (!packageName) {\n throw new Error(`\"${name}\" needs at least one letter or digit`);\n }\n\n const workspace = isInDotWorkspace(root);\n const template = templateDir();\n await mkdir(root, { recursive: true });\n for (const path of TEMPLATE_FILES) {\n await cp(join(template, path), join(root, path), { recursive: true });\n }\n const generated = projectFiles({\n name,\n packageName,\n dotVersion: workspace ? 'workspace:*' : `^${cliVersion()}`,\n workspace,\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 counter example: read from the repository, or from the copy the published CLI ships.\nfunction templateDir(): string {\n const example = join(cliRoot(), '../../examples/counter');\n return existsSync(example) ? example : join(cliRoot(), 'dist/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 { 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 { 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\nexport function describeError(error: unknown): string {\n const known =\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","import { watch } from 'node:fs';\nimport { relative, resolve, sep } from 'node:path';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, installedRuntime, loadProject } from '@monimesl/dot-compiler';\nimport { startSimulator } from '@monimesl/dot-simulator';\n\nimport { describeError, printBuildTime, printWarnings } from './report';\n\nexport interface DevOptions extends BuildOptions {\n port?: number | 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, ...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 startSimulator({\n dotDir: outDir,\n reactHostDir: installedRuntime(project.root).react.dir,\n name: project.dotJson.name,\n port,\n });\n if (firstError) {\n simulator.error(firstError);\n }\n console.log(`\\n Simulator running at: ${simulator.url}\\n`);\n\n const rebuilds = new RebuildQueue(async () => {\n const error = await buildApp();\n if (error) {\n simulator.error(error);\n } else {\n simulator.reload();\n }\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 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 simulator.close();\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 { spawn } from 'node:child_process';\nimport { relative } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\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 type { PackageManager } from './create/package-manager';\nimport {\n installedManagers,\n isPackageManager,\n launchedBy,\n PACKAGE_MANAGERS,\n} from './create/package-manager';\nimport { dev } from './dev';\nimport { describeError, printBuildTime, printWarnings } from './report';\n\nconst USAGE = `Usage:\n dotctl create [dir] [--name <name>] [--pm <npm|pnpm|yarn|bun>]\n Create a dot (asks for its name)\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\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\\`; the next free one is used if taken\n (default: ${DEFAULT_PORT})\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 name: { type: 'string' },\n pm: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n\n const [command, target] = positionals;\n if (command === 'create' && !values.help) {\n return createApp(target, values.name, values.pm);\n }\n if (values.help || (command !== 'build' && command !== 'dev')) {\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 });\n await new Promise((resolve) => process.once('SIGINT', resolve));\n await stop();\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 createApp(\n dir: string | undefined,\n name: string | undefined,\n packageManagerFlag: string | undefined,\n): Promise<number> {\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 { root, workspace } = await create({ name, dir: dir ?? toPackageName(name) });\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 if (await confirm('\\nInstall and start it now?')) {\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\nasync function confirm(question: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n return false;\n }\n const answer = await readAnswer(`${question} (Y/n)`, 'y');\n return answer !== undefined && answer.toLowerCase().startsWith('y');\n}\n\n// Shows the fallback after the question, as the answer an empty reply gives.\nasync function ask(question: string, fallback?: string): Promise<string | undefined> {\n const hint = fallback ? ` (${fallback})` : '';\n return readAnswer(`${question}${hint}`, fallback);\n}\n\nasync function readAnswer(prompt: string, fallback?: string): Promise<string | undefined> {\n if (!process.stdin.isTTY) {\n return fallback;\n }\n const readline = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await readline.question(`${prompt} `);\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\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 while (true) {\n const answer = await ask(`Package manager? ${installed.join(' / ')}`, fallback);\n if (answer === undefined) {\n return fallback;\n }\n if (isPackageManager(answer) && installed.includes(answer)) {\n return answer;\n }\n console.log(`Choose one of ${installed.join(', ')}.`);\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/create/template.ts","../src/create/create.ts","../src/create/page.ts","../src/create/package-manager.ts","../src/device/server.ts","../src/dev.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","// `starter` is one page to build on; `showcase` is a page for each feature, to read.\nexport const TEMPLATES = ['starter', 'showcase'] as const;\n\nexport type Template = (typeof TEMPLATES)[number];\n\nexport function isTemplate(name: string): name is Template {\n return (TEMPLATES as readonly string[]).includes(name);\n}\n\nexport interface 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 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: ['api.github.com', 'avatars.githubusercontent.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\nexport interface CreateOptions {\n name: string;\n dir: string;\n template?: Template;\n}\n\nexport interface 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 { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, 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 { CommandError } from '../report';\nimport { PAGE_FILES } from './template';\n\nexport interface CreatePageResult {\n // The page's folder, `<root>/pages/<path>`.\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/**\n * Adds a page to the dot around `cwd`: its folder under pages/, with its three files, listed last in\n * dot.ts.\n */\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\nfunction 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 { 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 { createHash, 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\nexport interface 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}\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=…&token=…`.\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\nexport const 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\nexport async function startDeviceServer({\n address = localNetworkAddress(),\n port = 0,\n onLog = () => {},\n onConnect = () => {},\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 const token = randomBytes(18).toString('base64url');\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 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 sendJson(response, { generation, hotSince, files, error });\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\n return {\n link: `${DEVICE_SCHEME}://connect?server=${encodeURIComponent(origin)}&token=${token}`,\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.\nexport function 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. Source maps stay\n// on the computer.\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 { watch } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\n\nimport type { BuildOptions } from '@monimesl/dot-compiler';\nimport { build, installedRuntime, loadProject, PAGES_DIR } from '@monimesl/dot-compiler';\nimport { startSimulator } from '@monimesl/dot-simulator';\nimport { renderUnicodeCompact } from 'uqr';\n\nimport type { DeviceServer } from './device/server';\nimport { startDeviceServer } from './device/server';\nimport { describeError, printBuildTime, printWarnings } from './report';\n\nexport interface 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 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 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 devices = await startDeviceServer({\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 }\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(' Scan this in a Dot example app on a phone:\\n');\n console.log(renderUnicodeCompact(link, { border: 2 }).replace(/^/gm, ' '));\n console.log(`\\n Or open the link on a device, an emulator or a simulator:\\n\\n ${link}\\n`);\n console.log(` Android emulator: adb shell am start -a android.intent.action.VIEW -d '${link}'`);\n console.log(` iOS Simulator: xcrun simctl openurl booted '${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 { spawn } from 'node:child_process';\nimport { relative } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\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, TEMPLATES } from './create/template';\nimport {\n installedManagers,\n isPackageManager,\n launchedBy,\n PACKAGE_MANAGERS,\n} from './create/package-manager';\nimport { dev } from './dev';\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 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\\`; the next free one is used if taken\n (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 === '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')) {\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 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 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 if (await confirm('\\nInstall and start it now?')) {\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\nasync function confirm(question: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n return false;\n }\n const answer = await readAnswer(`${question} (Y/n)`, 'y');\n return answer !== undefined && answer.toLowerCase().startsWith('y');\n}\n\n// Shows the fallback after the question, as the answer an empty reply gives.\nasync function ask(question: string, fallback?: string): Promise<string | undefined> {\n const hint = fallback ? ` (${fallback})` : '';\n return readAnswer(`${question}${hint}`, fallback);\n}\n\nasync function readAnswer(prompt: string, fallback?: string): Promise<string | undefined> {\n if (!process.stdin.isTTY) {\n return fallback;\n }\n const readline = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await readline.question(`${prompt} `);\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\nasync function chooseTemplate(): Promise<Template> {\n if (!process.stdin.isTTY) {\n return 'starter';\n }\n console.log(\n '\\nTemplates:\\n starter one page to build on\\n showcase a page for each feature, to read',\n );\n return chooseOne('Template?', TEMPLATES, '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 const fallback = installed.includes(suggested) ? suggested : installed[0]!;\n return chooseOne('Package manager?', installed, fallback);\n}\n\n// Asks until the answer is one of `options`; an empty answer, or none, is `fallback`.\nasync function chooseOne<Option extends string>(\n question: string,\n options: readonly Option[],\n fallback: Option,\n): Promise<Option> {\n while (true) {\n const answer = await ask(`${question} ${options.join(' / ')}`, fallback);\n if (answer === undefined) {\n return fallback;\n }\n const chosen = options.find((option) => option === answer);\n if (chosen) {\n return chosen;\n }\n console.log(`Choose one of ${options.join(', ')}.`);\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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"}
|