nx 23.0.0-beta.2 → 23.0.0-beta.21
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/dist/bin/init-local.js +11 -20
- package/dist/bin/nx.d.ts +1 -0
- package/dist/bin/nx.js +28 -2
- package/dist/plugins/package-json.js +4 -2
- package/dist/src/adapter/ngcli-adapter.d.ts +2 -1
- package/dist/src/adapter/ngcli-adapter.js +25 -2
- package/dist/src/ai/clone-ai-config-repo.js +20 -3
- package/dist/src/analytics/analytics.js +10 -1
- package/dist/src/command-line/add/completion.d.ts +1 -0
- package/dist/src/command-line/add/completion.js +15 -0
- package/dist/src/command-line/affected/completion.d.ts +1 -0
- package/dist/src/command-line/affected/completion.js +15 -0
- package/dist/src/command-line/completion/argv-layout.d.ts +6 -0
- package/dist/src/command-line/completion/argv-layout.js +19 -0
- package/dist/src/command-line/completion/command-completions.d.ts +19 -0
- package/dist/src/command-line/completion/command-completions.js +120 -0
- package/dist/src/command-line/completion/command-handlers.d.ts +30 -0
- package/dist/src/command-line/completion/command-handlers.js +69 -0
- package/dist/src/command-line/completion/command-object.d.ts +10 -0
- package/dist/src/command-line/completion/command-object.js +95 -0
- package/dist/src/command-line/completion/completion-providers.d.ts +21 -0
- package/dist/src/command-line/completion/completion-providers.js +194 -0
- package/dist/src/command-line/completion/infix-targets.d.ts +1 -0
- package/dist/src/command-line/completion/infix-targets.js +48 -0
- package/dist/src/command-line/completion/metadata.d.ts +22 -0
- package/dist/src/command-line/completion/metadata.js +71 -0
- package/dist/src/command-line/completion/registrations.d.ts +9 -0
- package/dist/src/command-line/completion/registrations.js +16 -0
- package/dist/src/command-line/completion/scripts/bash.sh +51 -0
- package/dist/src/command-line/completion/scripts/fish.fish +47 -0
- package/dist/src/command-line/completion/scripts/powershell.ps1 +52 -0
- package/dist/src/command-line/completion/scripts/zsh.zsh +69 -0
- package/dist/src/command-line/completion/scripts.d.ts +18 -0
- package/dist/src/command-line/completion/scripts.js +140 -0
- package/dist/src/command-line/completion/trigger.d.ts +3 -0
- package/dist/src/command-line/completion/trigger.js +21 -0
- package/dist/src/command-line/completion/value-completions.d.ts +3 -0
- package/dist/src/command-line/completion/value-completions.js +21 -0
- package/dist/src/command-line/examples.js +1 -1
- package/dist/src/command-line/format/format.js +15 -5
- package/dist/src/command-line/generate/completion.d.ts +1 -0
- package/dist/src/command-line/generate/completion.js +9 -0
- package/dist/src/command-line/graph/completion.d.ts +1 -0
- package/dist/src/command-line/graph/completion.js +13 -0
- package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +14 -18
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +1 -0
- package/dist/src/command-line/init/implementation/utils.d.ts +7 -1
- package/dist/src/command-line/init/implementation/utils.js +51 -14
- package/dist/src/command-line/migrate/agentic/capture-generator-output.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/capture-generator-output.js +100 -0
- package/dist/src/command-line/migrate/agentic/cli-args.d.ts +12 -0
- package/dist/src/command-line/migrate/agentic/cli-args.js +38 -0
- package/dist/src/command-line/migrate/agentic/definitions.d.ts +6 -0
- package/dist/src/command-line/migrate/agentic/definitions.js +98 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.js +68 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +87 -0
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +63 -0
- package/dist/src/command-line/migrate/agentic/handoff.js +183 -0
- package/dist/src/command-line/migrate/agentic/inception.d.ts +9 -0
- package/dist/src/command-line/migrate/agentic/inception.js +15 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +50 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +65 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +44 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +52 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +21 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +26 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +18 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +130 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +88 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +121 -0
- package/dist/src/command-line/migrate/agentic/runner.d.ts +33 -0
- package/dist/src/command-line/migrate/agentic/runner.js +442 -0
- package/dist/src/command-line/migrate/agentic/select.d.ts +14 -0
- package/dist/src/command-line/migrate/agentic/select.js +150 -0
- package/dist/src/command-line/migrate/agentic/types.d.ts +102 -0
- package/dist/src/command-line/migrate/agentic/types.js +2 -0
- package/dist/src/command-line/migrate/command-object.d.ts +1 -0
- package/dist/src/command-line/migrate/command-object.js +32 -7
- package/dist/src/command-line/migrate/migrate-commits.d.ts +50 -0
- package/dist/src/command-line/migrate/migrate-commits.js +102 -0
- package/dist/src/command-line/migrate/migrate-output.d.ts +180 -0
- package/dist/src/command-line/migrate/migrate-output.js +258 -0
- package/dist/src/command-line/migrate/migrate.d.ts +122 -12
- package/dist/src/command-line/migrate/migrate.js +1036 -217
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/migration-shape.js +13 -0
- package/dist/src/command-line/migrate/multi-major.d.ts +30 -0
- package/dist/src/command-line/migrate/multi-major.js +185 -0
- package/dist/src/command-line/migrate/prompt-files.d.ts +31 -0
- package/dist/src/command-line/migrate/prompt-files.js +141 -0
- package/dist/src/command-line/migrate/run-migration-process.js +28 -6
- package/dist/src/command-line/migrate/safe-prompt.d.ts +28 -0
- package/dist/src/command-line/migrate/safe-prompt.js +49 -0
- package/dist/src/command-line/migrate/update-filters.d.ts +11 -0
- package/dist/src/command-line/migrate/update-filters.js +44 -0
- package/dist/src/command-line/migrate/version-utils.d.ts +6 -0
- package/dist/src/command-line/migrate/version-utils.js +59 -0
- package/dist/src/command-line/nx-commands.js +9 -0
- package/dist/src/command-line/release/config/config.d.ts +3 -6
- package/dist/src/command-line/release/config/config.js +77 -45
- package/dist/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
- package/dist/src/command-line/release/config/use-legacy-versioning.js +8 -0
- package/dist/src/command-line/release/utils/release-graph.js +2 -3
- package/dist/src/command-line/release/utils/repository-git-tags.js +1 -1
- package/dist/src/command-line/release/utils/resolve-changelog-renderer.js +7 -19
- package/dist/src/command-line/release/version/resolve-current-version.js +1 -1
- package/dist/src/command-line/release/version/version-actions.js +3 -7
- package/dist/src/command-line/report/report.js +2 -2
- package/dist/src/command-line/run/completion.d.ts +1 -0
- package/dist/src/command-line/run/completion.js +7 -0
- package/dist/src/command-line/run-many/completion.d.ts +1 -0
- package/dist/src/command-line/run-many/completion.js +13 -0
- package/dist/src/command-line/show/completion.d.ts +1 -0
- package/dist/src/command-line/show/completion.js +27 -0
- package/dist/src/command-line/show/show-target/info.d.ts +1 -0
- package/dist/src/command-line/show/show-target/info.js +100 -19
- package/dist/src/command-line/watch/command-object.js +24 -4
- package/dist/src/command-line/watch/completion.d.ts +1 -0
- package/dist/src/command-line/watch/completion.js +10 -0
- package/dist/src/command-line/watch/watch.d.ts +7 -0
- package/dist/src/command-line/watch/watch.js +1 -1
- package/dist/src/config/misc-interfaces.d.ts +25 -2
- package/dist/src/config/nx-json.d.ts +43 -56
- package/dist/src/config/schema-utils.d.ts +21 -0
- package/dist/src/config/schema-utils.js +92 -18
- package/dist/src/config/task-graph.d.ts +4 -107
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.css +2 -3
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +1 -1
- package/dist/src/daemon/server/file-watching/route-workspace-changes.d.ts +9 -0
- package/dist/src/daemon/server/file-watching/route-workspace-changes.js +76 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +45 -11
- package/dist/src/daemon/server/server.js +4 -43
- package/dist/src/daemon/server/start.d.ts +1 -1
- package/dist/src/daemon/server/start.js +2 -0
- package/dist/src/devkit-exports.d.ts +2 -2
- package/dist/src/devkit-internals.d.ts +5 -1
- package/dist/src/devkit-internals.js +17 -1
- package/dist/src/executors/run-commands/running-tasks.d.ts +7 -0
- package/dist/src/executors/run-commands/running-tasks.js +178 -105
- package/dist/src/executors/run-script/run-script.impl.js +3 -10
- package/dist/src/executors/utils/convert-nx-executor.js +1 -1
- package/dist/src/hasher/hash-plan-inspector.d.ts +1 -1
- package/dist/src/hasher/task-hasher.js +6 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +0 -3
- package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +6 -2
- package/dist/src/migrations/update-17-0-0/move-cache-directory.md +31 -0
- package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +20 -4
- package/dist/src/migrations/update-20-0-0/move-use-daemon-process.md +27 -0
- package/dist/src/migrations/update-20-0-1/use-legacy-cache.md +24 -0
- package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.md +49 -0
- package/dist/src/migrations/update-21-0-0/release-version-config-changes.md +54 -0
- package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.md +28 -0
- package/dist/src/migrations/update-21-0-0/remove-legacy-cache.md +22 -0
- package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.md +11 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.d.ts +2 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +16 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +9 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +18 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +35 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +139 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.md +66 -0
- package/dist/src/native/index.d.ts +79 -2
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/npm-parser.js +37 -19
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +51 -4
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +12 -4
- package/dist/src/plugins/js/utils/packages.js +1 -1
- package/dist/src/plugins/js/utils/register.d.ts +103 -14
- package/dist/src/plugins/js/utils/register.js +434 -39
- package/dist/src/plugins/js/utils/typescript.d.ts +7 -0
- package/dist/src/plugins/js/utils/typescript.js +39 -0
- package/dist/src/plugins/package-json/create-nodes.d.ts +3 -2
- package/dist/src/plugins/package-json/create-nodes.js +7 -5
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +2 -1
- package/dist/src/project-graph/build-project-graph.d.ts +5 -0
- package/dist/src/project-graph/build-project-graph.js +6 -2
- package/dist/src/project-graph/file-map-utils.d.ts +5 -0
- package/dist/src/project-graph/file-map-utils.js +10 -1
- package/dist/src/project-graph/plugins/get-plugins.d.ts +7 -2
- package/dist/src/project-graph/plugins/get-plugins.js +8 -5
- package/dist/src/project-graph/plugins/isolation/plugin-worker.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +2 -0
- package/dist/src/project-graph/plugins/resolve-plugin.d.ts +7 -4
- package/dist/src/project-graph/plugins/resolve-plugin.js +152 -33
- package/dist/src/project-graph/plugins/tasks-execution-hooks.js +4 -2
- package/dist/src/project-graph/plugins/transpiler.d.ts +12 -0
- package/dist/src/project-graph/plugins/transpiler.js +37 -0
- package/dist/src/project-graph/plugins/utils.js +13 -7
- package/dist/src/project-graph/project-graph.js +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +95 -4
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +515 -68
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +13 -5
- package/dist/src/project-graph/utils/project-configuration-utils.js +14 -6
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -1
- package/dist/src/tasks-runner/create-task-graph.d.ts +4 -4
- package/dist/src/tasks-runner/create-task-graph.js +1 -1
- package/dist/src/tasks-runner/default-tasks-runner.d.ts +0 -2
- package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.js +11 -6
- package/dist/src/tasks-runner/init-tasks-runner.d.ts +0 -15
- package/dist/src/tasks-runner/init-tasks-runner.js +0 -63
- package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +18 -0
- package/dist/src/tasks-runner/legacy-depends-on-warning.js +109 -0
- package/dist/src/tasks-runner/life-cycle.d.ts +7 -8
- package/dist/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +6 -6
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +13 -2
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -5
- package/dist/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +11 -2
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/run-command.js +8 -11
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
- package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
- package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
- package/dist/src/tasks-runner/task-env.d.ts +1 -1
- package/dist/src/tasks-runner/task-env.js +6 -1
- package/dist/src/tasks-runner/task-orchestrator.d.ts +11 -1
- package/dist/src/tasks-runner/task-orchestrator.js +112 -38
- package/dist/src/tasks-runner/tasks-schedule.js +3 -3
- package/dist/src/tasks-runner/utils.d.ts +7 -8
- package/dist/src/tasks-runner/utils.js +23 -27
- package/dist/src/utils/child-process.js +2 -2
- package/dist/src/utils/compile-cache.d.ts +24 -0
- package/dist/src/utils/compile-cache.js +49 -0
- package/dist/src/utils/enable-compile-cache.d.ts +1 -0
- package/dist/src/utils/enable-compile-cache.js +7 -0
- package/dist/src/utils/fileutils.d.ts +0 -8
- package/dist/src/utils/fileutils.js +0 -40
- package/dist/src/utils/git-utils.d.ts +15 -0
- package/dist/src/utils/git-utils.js +138 -0
- package/dist/src/utils/handle-import.d.ts +4 -1
- package/dist/src/utils/handle-import.js +56 -2
- package/dist/src/utils/has-nx-js-plugin.d.ts +9 -0
- package/dist/src/utils/has-nx-js-plugin.js +24 -0
- package/dist/src/utils/installed-nx-version.d.ts +14 -4
- package/dist/src/utils/installed-nx-version.js +54 -7
- package/dist/src/utils/logger.d.ts +12 -1
- package/dist/src/utils/logger.js +57 -36
- package/dist/src/utils/nx-key.d.ts +0 -1
- package/dist/src/utils/nx-key.js +20 -23
- package/dist/src/utils/nx-package-group.d.ts +8 -0
- package/dist/src/utils/nx-package-group.js +15 -0
- package/dist/src/utils/output.d.ts +3 -2
- package/dist/src/utils/output.js +29 -28
- package/dist/src/utils/package-json.d.ts +14 -1
- package/dist/src/utils/package-json.js +20 -21
- package/dist/src/utils/perf-logging.js +3 -1
- package/dist/src/utils/plugin-cache-utils.d.ts +13 -4
- package/dist/src/utils/plugin-cache-utils.js +23 -13
- package/dist/src/utils/plugins/local-plugins.d.ts +18 -0
- package/dist/src/utils/plugins/local-plugins.js +30 -0
- package/dist/src/utils/tar.d.ts +8 -0
- package/dist/src/utils/tar.js +44 -0
- package/migrations.json +16 -0
- package/package.json +28 -28
- package/schemas/nx-schema.json +114 -80
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.d.ts +0 -7
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.js +0 -155
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.d.ts +0 -16
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.js +0 -121
|
@@ -52,7 +52,7 @@ export declare class AppLifeCycle {
|
|
|
52
52
|
export declare class ChildProcess {
|
|
53
53
|
getParserAndWriter(): ExternalObject<[ParserArc, WriterArc]>
|
|
54
54
|
getPid(): number
|
|
55
|
-
kill(signal?: NodeJS.Signals): void
|
|
55
|
+
kill(signal?: NodeJS.Signals | number): void
|
|
56
56
|
onExit(callback: (message: string) => void): void
|
|
57
57
|
onOutput(callback: (message: string) => void): void
|
|
58
58
|
cleanup(): void
|
|
@@ -206,6 +206,18 @@ export declare class TaskHasher {
|
|
|
206
206
|
hashPlans(hashPlans: ExternalObject<Record<string, Array<HashInstruction>>>, perTaskEnvs: Record<string, Record<string, string>>, cwd: string, collectTaskInputs?: boolean | undefined | null): Record<string, HashDetails>
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
export declare class TaskInvocationTracker {
|
|
210
|
+
constructor(db: ExternalObject<NxDbConnection>, rootPid: number)
|
|
211
|
+
/** Register a task as invoked. Throws if the task was already registered (loop detected). */
|
|
212
|
+
registerTask(parentPid: number, taskId: string): void
|
|
213
|
+
/** Remove a task invocation record after task completes. */
|
|
214
|
+
unregisterTask(taskId: string): void
|
|
215
|
+
/** Get all invocations for this root_pid, ordered by creation time. */
|
|
216
|
+
getInvocationChain(): Array<InvocationRecord>
|
|
217
|
+
/** Clean up stale invocations older than 1 day (handles PID recycling). */
|
|
218
|
+
cleanupStale(): void
|
|
219
|
+
}
|
|
220
|
+
|
|
209
221
|
export declare class Watcher {
|
|
210
222
|
origin: string
|
|
211
223
|
/**
|
|
@@ -454,6 +466,11 @@ export declare function installNxConsole(): Promise<boolean>
|
|
|
454
466
|
|
|
455
467
|
export declare function installNxConsoleForEditor(editor: SupportedEditor): Promise<boolean>
|
|
456
468
|
|
|
469
|
+
export interface InvocationRecord {
|
|
470
|
+
parentPid: number
|
|
471
|
+
taskId: string
|
|
472
|
+
}
|
|
473
|
+
|
|
457
474
|
export const IS_WASM: boolean
|
|
458
475
|
|
|
459
476
|
/**
|
|
@@ -472,6 +489,23 @@ export interface JsonInput {
|
|
|
472
489
|
excludeFields?: Array<string>
|
|
473
490
|
}
|
|
474
491
|
|
|
492
|
+
/**
|
|
493
|
+
* Kill a process and all its descendants (fire-and-forget).
|
|
494
|
+
*
|
|
495
|
+
* Sends the requested signal but does NOT wait for processes to exit.
|
|
496
|
+
* Use `killProcessTreeGraceful` when cleanup handlers must run.
|
|
497
|
+
*/
|
|
498
|
+
export declare function killProcessTree(rootPid: number, signal?: string | number | undefined | null): void
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Kill a process tree gracefully: signal → wait → SIGKILL.
|
|
502
|
+
*
|
|
503
|
+
* Signals leaf processes first, waits for them to exit, then signals
|
|
504
|
+
* their parents (now leaves). Repeats until the tree is empty or the
|
|
505
|
+
* grace period expires, then force-kills survivors.
|
|
506
|
+
*/
|
|
507
|
+
export declare function killProcessTreeGraceful(rootPid: number, signal?: string | number | undefined | null, gracePeriodMs?: number | undefined | null): Promise<void>
|
|
508
|
+
|
|
475
509
|
export declare function logDebug(message: string): void
|
|
476
510
|
|
|
477
511
|
/** Combined metadata for groups and processes */
|
|
@@ -581,26 +615,66 @@ export interface Target {
|
|
|
581
615
|
parallelism?: boolean
|
|
582
616
|
}
|
|
583
617
|
|
|
618
|
+
/** A representation of the invocation of an Executor */
|
|
584
619
|
export interface Task {
|
|
620
|
+
/** Unique ID */
|
|
585
621
|
id: string
|
|
622
|
+
/** Details about which project, target, and configuration to run. */
|
|
586
623
|
target: TaskTarget
|
|
624
|
+
/** Overrides for the configured options of the target */
|
|
625
|
+
overrides: Record<string, unknown>
|
|
626
|
+
/** The outputs the task may produce */
|
|
587
627
|
outputs: Array<string>
|
|
628
|
+
/** Root of the project the task belongs to */
|
|
588
629
|
projectRoot?: string
|
|
630
|
+
/** Hash of the task which is used for caching. */
|
|
631
|
+
hash?: string
|
|
632
|
+
/** Details about the composition of the hash */
|
|
633
|
+
hashDetails?: TaskHashDetails
|
|
634
|
+
/** Unix timestamp of when a Batch Task starts */
|
|
589
635
|
startTime?: number
|
|
636
|
+
/** Unix timestamp of when a Batch Task ends */
|
|
590
637
|
endTime?: number
|
|
638
|
+
/** Determines if a given task should be cacheable. */
|
|
639
|
+
cache: boolean
|
|
640
|
+
/** Determines if a given task should be parallelizable. */
|
|
641
|
+
parallelism?: boolean
|
|
642
|
+
/** This denotes if the task runs continuously */
|
|
591
643
|
continuous?: boolean
|
|
592
644
|
}
|
|
593
645
|
|
|
646
|
+
/** Graph of Tasks to be executed */
|
|
594
647
|
export interface TaskGraph {
|
|
648
|
+
/** IDs of Tasks which do not have any dependencies and are thus ready to execute immediately */
|
|
595
649
|
roots: Array<string>
|
|
650
|
+
/** Map of Task IDs to Tasks */
|
|
596
651
|
tasks: Record<string, Task>
|
|
652
|
+
/** Map of Task IDs to IDs of tasks which the task depends on */
|
|
597
653
|
dependencies: Record<string, Array<string>>
|
|
598
654
|
continuousDependencies: Record<string, Array<string>>
|
|
599
655
|
}
|
|
600
656
|
|
|
657
|
+
/** Details about the composition of a task's hash */
|
|
658
|
+
export interface TaskHashDetails {
|
|
659
|
+
/** Command of the task */
|
|
660
|
+
command: string
|
|
661
|
+
/** Hashes of inputs used in the hash */
|
|
662
|
+
nodes: Record<string, string>
|
|
663
|
+
/** Hashes of implicit dependencies which are included in the hash */
|
|
664
|
+
implicitDeps?: Record<string, string>
|
|
665
|
+
/** Hash of the runtime environment which the task was executed */
|
|
666
|
+
runtime?: Record<string, string>
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* The result of a completed Task.
|
|
671
|
+
*
|
|
672
|
+
* Task timing information (start and end timestamps) is available
|
|
673
|
+
* on the Task object itself via `Task.startTime` and `Task.endTime`.
|
|
674
|
+
*/
|
|
601
675
|
export interface TaskResult {
|
|
602
676
|
task: Task
|
|
603
|
-
status:
|
|
677
|
+
status: 'success' | 'failure' | 'skipped' | 'stopped' | 'local-cache-kept-existing' | 'local-cache' | 'remote-cache'
|
|
604
678
|
code: number
|
|
605
679
|
terminalOutput?: string
|
|
606
680
|
}
|
|
@@ -627,8 +701,11 @@ export declare const enum TaskStatus {
|
|
|
627
701
|
}
|
|
628
702
|
|
|
629
703
|
export interface TaskTarget {
|
|
704
|
+
/** The project for which the task belongs to */
|
|
630
705
|
project: string
|
|
706
|
+
/** The target name which the task should invoke */
|
|
631
707
|
target: string
|
|
708
|
+
/** The configuration of the target which the task invokes */
|
|
632
709
|
configuration?: string
|
|
633
710
|
}
|
|
634
711
|
|
|
@@ -591,6 +591,7 @@ module.exports.RunningTasksService = nativeBinding.RunningTasksService
|
|
|
591
591
|
module.exports.RustPseudoTerminal = nativeBinding.RustPseudoTerminal
|
|
592
592
|
module.exports.TaskDetails = nativeBinding.TaskDetails
|
|
593
593
|
module.exports.TaskHasher = nativeBinding.TaskHasher
|
|
594
|
+
module.exports.TaskInvocationTracker = nativeBinding.TaskInvocationTracker
|
|
594
595
|
module.exports.Watcher = nativeBinding.Watcher
|
|
595
596
|
module.exports.WorkspaceContext = nativeBinding.WorkspaceContext
|
|
596
597
|
module.exports.BatchStatus = nativeBinding.BatchStatus
|
|
@@ -620,6 +621,8 @@ module.exports.installNxConsoleForEditor = nativeBinding.installNxConsoleForEdit
|
|
|
620
621
|
module.exports.IS_WASM = nativeBinding.IS_WASM
|
|
621
622
|
module.exports.isAiAgent = nativeBinding.isAiAgent
|
|
622
623
|
module.exports.isEditorInstalled = nativeBinding.isEditorInstalled
|
|
624
|
+
module.exports.killProcessTree = nativeBinding.killProcessTree
|
|
625
|
+
module.exports.killProcessTreeGraceful = nativeBinding.killProcessTreeGraceful
|
|
623
626
|
module.exports.logDebug = nativeBinding.logDebug
|
|
624
627
|
module.exports.parseTaskStatus = nativeBinding.parseTaskStatus
|
|
625
628
|
module.exports.remove = nativeBinding.remove
|
|
Binary file
|
|
Binary file
|
|
@@ -270,27 +270,45 @@ function stringifyNpmLockfile(graph, rootLockFileContent, packageJson) {
|
|
|
270
270
|
}
|
|
271
271
|
return JSON.stringify(output, null, 2);
|
|
272
272
|
}
|
|
273
|
+
const WORKSPACE_DEP_TYPES = [
|
|
274
|
+
'dependencies',
|
|
275
|
+
'optionalDependencies',
|
|
276
|
+
'peerDependencies',
|
|
277
|
+
];
|
|
273
278
|
function mapWorkspaceModules(packageJson, rootLockFile, workspaceModules) {
|
|
274
279
|
const output = {};
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
280
|
+
const snapshotsByName = new Map();
|
|
281
|
+
for (const snapshot of Object.values(rootLockFile.packages || rootLockFile.dependencies || {})) {
|
|
282
|
+
if (snapshot.name)
|
|
283
|
+
snapshotsByName.set(snapshot.name, snapshot);
|
|
284
|
+
}
|
|
285
|
+
// Walk transitive workspace deps so every workspace package
|
|
286
|
+
// copy-workspace-modules writes to disk has matching lockfile entries.
|
|
287
|
+
// Without this, `npm ci` errors with "Missing: <pkg> from lock file".
|
|
288
|
+
const queue = Object.keys(packageJson.dependencies ?? {});
|
|
289
|
+
const visited = new Set();
|
|
290
|
+
while (queue.length > 0) {
|
|
291
|
+
const pkgName = queue.shift();
|
|
292
|
+
if (visited.has(pkgName) || !workspaceModules.has(pkgName))
|
|
293
|
+
continue;
|
|
294
|
+
visited.add(pkgName);
|
|
295
|
+
const snapshot = snapshotsByName.get(pkgName);
|
|
296
|
+
output[`node_modules/${pkgName}`] = {
|
|
297
|
+
version: `file:./workspace_modules/${pkgName}`,
|
|
298
|
+
resolved: `workspace_modules/${pkgName}`,
|
|
299
|
+
link: true,
|
|
300
|
+
};
|
|
301
|
+
output[`workspace_modules/${pkgName}`] = {
|
|
302
|
+
name: pkgName,
|
|
303
|
+
version: `0.0.1`,
|
|
304
|
+
dependencies: snapshot?.dependencies,
|
|
305
|
+
};
|
|
306
|
+
for (const depType of WORKSPACE_DEP_TYPES) {
|
|
307
|
+
const deps = snapshot?.[depType];
|
|
308
|
+
if (!deps)
|
|
309
|
+
continue;
|
|
310
|
+
for (const depName of Object.keys(deps))
|
|
311
|
+
queue.push(depName);
|
|
294
312
|
}
|
|
295
313
|
}
|
|
296
314
|
return output;
|
|
@@ -14,6 +14,11 @@ const project_graph_pruning_1 = require("./project-graph-pruning");
|
|
|
14
14
|
const path_1 = require("path");
|
|
15
15
|
const get_workspace_packages_from_graph_1 = require("../utils/get-workspace-packages-from-graph");
|
|
16
16
|
const semver_1 = require("semver");
|
|
17
|
+
const WORKSPACE_DEP_TYPES = [
|
|
18
|
+
'dependencies',
|
|
19
|
+
'optionalDependencies',
|
|
20
|
+
'peerDependencies',
|
|
21
|
+
];
|
|
17
22
|
let currentLockFileHash;
|
|
18
23
|
let parsedLockFile;
|
|
19
24
|
function parsePnpmLockFile(lockFileContent, lockFileHash) {
|
|
@@ -389,13 +394,55 @@ function stringifyPnpmLockfile(graph, rootLockFileContent, packageJson, workspac
|
|
|
389
394
|
const { lockfileVersion, packages, importers } = data;
|
|
390
395
|
const { snapshot: rootSnapshot, importers: requiredImporters } = mapRootSnapshot(packageJson, importers, packages, graph, +lockfileVersion, workspaceRoot);
|
|
391
396
|
const snapshots = mapSnapshots(data.packages, graph.externalNodes, +lockfileVersion);
|
|
397
|
+
const workspaceModules = (0, get_workspace_packages_from_graph_1.getWorkspacePackagesFromGraph)(graph);
|
|
398
|
+
// Walk transitive workspace deps so every package copy-workspace-modules
|
|
399
|
+
// writes to disk has a matching importer block. Without this, pnpm errors
|
|
400
|
+
// with ERR_PNPM_OUTDATED_LOCKFILE on transitive workspace chains.
|
|
401
|
+
const allRequiredImporters = { ...requiredImporters };
|
|
402
|
+
const queue = Object.keys(requiredImporters);
|
|
403
|
+
while (queue.length > 0) {
|
|
404
|
+
const pkgName = queue.shift();
|
|
405
|
+
const importer = importers[allRequiredImporters[pkgName]];
|
|
406
|
+
if (!importer)
|
|
407
|
+
continue;
|
|
408
|
+
for (const depType of WORKSPACE_DEP_TYPES) {
|
|
409
|
+
const deps = importer[depType];
|
|
410
|
+
if (!deps)
|
|
411
|
+
continue;
|
|
412
|
+
for (const depName of Object.keys(deps)) {
|
|
413
|
+
if (workspaceModules.has(depName) && !allRequiredImporters[depName]) {
|
|
414
|
+
allRequiredImporters[depName] =
|
|
415
|
+
workspaceModules.get(depName).data.root;
|
|
416
|
+
queue.push(depName);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
392
421
|
const workspaceDependencyImporters = {};
|
|
393
|
-
for (const [packageName, importerPath] of Object.entries(
|
|
422
|
+
for (const [packageName, importerPath] of Object.entries(allRequiredImporters)) {
|
|
394
423
|
const baseImporter = importers[importerPath];
|
|
395
|
-
if (baseImporter)
|
|
396
|
-
|
|
397
|
-
|
|
424
|
+
if (!baseImporter)
|
|
425
|
+
continue;
|
|
426
|
+
const importer = structuredClone(baseImporter);
|
|
427
|
+
for (const depType of WORKSPACE_DEP_TYPES) {
|
|
428
|
+
const deps = importer[depType];
|
|
429
|
+
if (!deps)
|
|
430
|
+
continue;
|
|
431
|
+
for (const depName of Object.keys(deps)) {
|
|
432
|
+
if (!workspaceModules.has(depName))
|
|
433
|
+
continue;
|
|
434
|
+
// All workspace modules are siblings under workspace_modules/, so the
|
|
435
|
+
// relative path between them is relative(packageName, depName).
|
|
436
|
+
// Specifier must match the file: ref copy-workspace-modules writes
|
|
437
|
+
// to the package's package.json — pnpm errors on a mismatch.
|
|
438
|
+
const rel = (0, path_1.relative)(packageName, depName).split(path_1.sep).join('/');
|
|
439
|
+
if (!importer.specifiers)
|
|
440
|
+
importer.specifiers = {};
|
|
441
|
+
importer.specifiers[depName] = `file:${rel}`;
|
|
442
|
+
deps[depName] = `link:${rel}`;
|
|
443
|
+
}
|
|
398
444
|
}
|
|
445
|
+
workspaceDependencyImporters[`workspace_modules/${packageName}`] = importer;
|
|
399
446
|
}
|
|
400
447
|
const output = {
|
|
401
448
|
...data,
|
|
@@ -115,11 +115,19 @@ function traverseNode(graph, builder, node) {
|
|
|
115
115
|
builder.addStaticDependency(node.name, dep.target);
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
|
-
function traverseWorkspaceNode(graph, builder, node) {
|
|
118
|
+
function traverseWorkspaceNode(graph, builder, node, visited = new Set()) {
|
|
119
|
+
if (visited.has(node.name))
|
|
120
|
+
return;
|
|
121
|
+
visited.add(node.name);
|
|
119
122
|
graph.dependencies[node.name]?.forEach((dep) => {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
traverseNode(graph, builder,
|
|
123
|
+
const externalDepNode = graph.externalNodes[dep.target];
|
|
124
|
+
if (externalDepNode) {
|
|
125
|
+
traverseNode(graph, builder, externalDepNode);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const workspaceDepNode = graph.nodes[dep.target];
|
|
129
|
+
if (workspaceDepNode) {
|
|
130
|
+
traverseWorkspaceNode(graph, builder, workspaceDepNode, visited);
|
|
123
131
|
}
|
|
124
132
|
});
|
|
125
133
|
}
|
|
@@ -8,7 +8,7 @@ function getWorkspacePackagesMetadata(projects) {
|
|
|
8
8
|
const wildcardEntryPointsToProjectMap = {};
|
|
9
9
|
const packageToProjectMap = {};
|
|
10
10
|
for (const project of Object.values(projects)) {
|
|
11
|
-
const metadata = 'data' in project ? project.data.metadata : project.metadata;
|
|
11
|
+
const metadata = ('data' in project ? project.data.metadata : project.metadata);
|
|
12
12
|
if (!metadata?.js) {
|
|
13
13
|
continue;
|
|
14
14
|
}
|
|
@@ -1,31 +1,120 @@
|
|
|
1
1
|
import type { TsConfigOptions } from 'ts-node';
|
|
2
2
|
import type { CompilerOptions } from 'typescript';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Force-register an ESM loader (`@swc-node/register/esm` if available, else
|
|
5
|
+
* `ts-node/esm`) via `Module.register` so dynamic `import()` of TS files
|
|
6
|
+
* goes through a transpiler.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* **IMPORTANT — global side effect:** `Module.register` is one-shot per
|
|
9
|
+
* process and applies to *every* subsequent ESM resolution in the process.
|
|
10
|
+
* Calling this trades native Node.js TypeScript stripping for transpiled
|
|
11
|
+
* loading on the dynamic-import path for the rest of the run. CJS
|
|
12
|
+
* `require()` is unaffected (different hook), so `.cts` files via require
|
|
13
|
+
* keep using native strip + swc-node's `Module._extensions` hook.
|
|
10
14
|
*
|
|
11
|
-
*
|
|
15
|
+
* Required for the niche case where an ESM config (`.mts` or `.ts` resolved
|
|
16
|
+
* as ESM) combines top-level await with TypeScript syntax that native strip
|
|
17
|
+
* can't handle (`enum`, runtime `namespace`, etc.). TLA forces dynamic
|
|
18
|
+
* `import()`, which bypasses the CJS hook chain - the only way to intercept
|
|
19
|
+
* is `Module.register`.
|
|
20
|
+
*
|
|
21
|
+
* Idempotent: subsequent calls are no-ops.
|
|
22
|
+
*
|
|
23
|
+
* Throws if neither `@swc-node/register` nor `ts-node` is installed.
|
|
12
24
|
*/
|
|
13
|
-
export declare function
|
|
25
|
+
export declare function forceRegisterEsmLoader(): void;
|
|
14
26
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
27
|
+
* Whether Nx will defer to Node's native TypeScript stripping for the next
|
|
28
|
+
* `.ts` load. Mirrors the gate used by `loadTsFile`/`registerTsProject` so
|
|
29
|
+
* other registration sites (e.g. plugin transpiler) can stay aligned.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isNativeStripPreferred(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* This function registers either ts-node or swc-node to transpile TypeScript files on the fly.
|
|
34
|
+
* It also registers tsconfig-paths to handle path mapping based on the provided tsconfig.
|
|
17
35
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* workspace path mapping will not, for example).
|
|
36
|
+
* The TypeScript transpiler registration is done regardless of NX_PREFER_NODE_STRIP_TYPES.
|
|
37
|
+
* If you want to skip transpiler registration, it is recommended that you check `process.features.typescript`.
|
|
21
38
|
*
|
|
22
39
|
* @returns cleanup function
|
|
23
|
-
* @deprecated This signature will be removed in Nx v19. You should pass the full path to the tsconfig in the first argument.
|
|
24
40
|
*/
|
|
25
|
-
export declare function registerTsProject(
|
|
41
|
+
export declare function registerTsProject(tsConfigPath: string): () => void;
|
|
26
42
|
export declare function getSwcTranspiler(compilerOptions: CompilerOptions): (...args: unknown[]) => unknown;
|
|
27
43
|
export declare function getTsNodeTranspiler(compilerOptions: CompilerOptions, tsNodeOptions?: TsConfigOptions, preferTsNode?: boolean): (...args: unknown[]) => unknown;
|
|
28
44
|
export declare function getTranspiler(compilerOptions: CompilerOptions, tsConfigRaw?: unknown): () => (...args: unknown[]) => unknown;
|
|
45
|
+
/**
|
|
46
|
+
* Node.js throws this code when native type stripping hits an unsupported
|
|
47
|
+
* construct (enum, runtime namespace, legacy decorators, import = require,
|
|
48
|
+
* parameter properties on older Node, etc.).
|
|
49
|
+
*
|
|
50
|
+
* Exported for tests.
|
|
51
|
+
*/
|
|
52
|
+
export declare function isNativeTypeStripError(err: unknown): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* A SyntaxError thrown while parsing a forced-CJS file (`.cts`/`.cjs`) as
|
|
55
|
+
* CommonJS - typically ESM syntax in a CJS file (e.g. `export default` in
|
|
56
|
+
* `.cts`). Pre-v23 this worked because swc-node's CJS hook compiled away the
|
|
57
|
+
* ESM syntax; under native strip swc-node isn't registered, so the file
|
|
58
|
+
* reaches Node's strict CJS parser. swc-node tolerates ESM syntax in `.cts`
|
|
59
|
+
* (`register()` forces `module: commonjs` regardless of extension), so
|
|
60
|
+
* escalating to the swc/ts-node fallback recovers the legacy behavior.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isCjsSyntaxError(err: unknown, filePath: string): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* A ReferenceError from Node treating a `.ts`/`.mts` file as ESM and the file
|
|
65
|
+
* relying on a CJS-only global: `require`, `__dirname`, or `__filename`.
|
|
66
|
+
* Pre-v23 swc-node compiled `.ts` to CJS where these globals exist; under
|
|
67
|
+
* native strip Node detects ESM via `import`/`export` syntax and these globals
|
|
68
|
+
* are undefined. Registering swc/ts-node compiles ESM->CJS and restores the
|
|
69
|
+
* legacy globals.
|
|
70
|
+
*/
|
|
71
|
+
export declare function isRequireInEsmScopeError(err: unknown, filePath: string): boolean;
|
|
72
|
+
export declare function isTsEsmSyntaxError(err: unknown, filePath: string): boolean;
|
|
73
|
+
export declare function isTsEsmNamedExportLinkageError(err: unknown, filePath: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Load a TypeScript file via `require()`.
|
|
76
|
+
*
|
|
77
|
+
* When the runtime exposes native TypeScript stripping
|
|
78
|
+
* (`process.features.typescript`) and the user hasn't opted out via
|
|
79
|
+
* `NX_PREFER_NODE_STRIP_TYPES=false`, the file loads directly with no
|
|
80
|
+
* swc/ts-node and no tsconfig-paths registration. If Node throws on an
|
|
81
|
+
* unsupported construct (enum, runtime namespace, legacy decorators, etc.),
|
|
82
|
+
* this registers swc/ts-node + tsconfig-paths and retries - matching the
|
|
83
|
+
* pre-v23 registration. Set `NX_DISABLE_TSCONFIG_PATHS=true` to skip
|
|
84
|
+
* tsconfig-paths even on fallback (useful when relying on package manager
|
|
85
|
+
* workspaces). Set `NX_VERBOSE_LOGGING=true` to log when fallback triggers.
|
|
86
|
+
*
|
|
87
|
+
* When native strip is opted out (`NX_PREFER_NODE_STRIP_TYPES=false` or
|
|
88
|
+
* unsupported Node), uses the legacy `registerTsProject` path.
|
|
89
|
+
*
|
|
90
|
+
* `tsConfigPath` is only consulted on the swc/ts-node fallback path (for
|
|
91
|
+
* compilerOptions) and for tsconfig-paths registration. Native strip ignores
|
|
92
|
+
* it. When omitted, defaults to the workspace root tsconfig.
|
|
93
|
+
*
|
|
94
|
+
* Note on ESM: Node 22.12+ supports `require()` of synchronous ESM by default,
|
|
95
|
+
* so most ESM `.ts` configs load via this function without issue. Modules
|
|
96
|
+
* that use top-level await throw `ERR_REQUIRE_ASYNC_MODULE` and must be
|
|
97
|
+
* loaded with dynamic `import()` instead. `ERR_REQUIRE_ESM` (legacy code)
|
|
98
|
+
* bubbles unchanged for the rare case it still fires, so async-aware callers
|
|
99
|
+
* can dispatch to `import()`.
|
|
100
|
+
*
|
|
101
|
+
* @returns the loaded module
|
|
102
|
+
*/
|
|
103
|
+
export declare function loadTsFile<T = any>(filePath: string, tsConfigPath?: string): T;
|
|
104
|
+
/**
|
|
105
|
+
* Plain `require()` with a lazy `tsconfig-paths` fallback. Use for files that
|
|
106
|
+
* are NOT TypeScript (no transpilation needed) but may still import workspace
|
|
107
|
+
* packages through TS path aliases (e.g. a `.js` changelog renderer that
|
|
108
|
+
* `require`s `@my-org/lib`).
|
|
109
|
+
*
|
|
110
|
+
* `tsconfig-paths` is only registered after the first `require()` fails with
|
|
111
|
+
* a module-resolution error, so workspaces that resolve aliases through
|
|
112
|
+
* package-manager symlinks pay nothing. Set `NX_DISABLE_TSCONFIG_PATHS=true`
|
|
113
|
+
* to skip the fallback entirely.
|
|
114
|
+
*
|
|
115
|
+
* @returns the loaded module
|
|
116
|
+
*/
|
|
117
|
+
export declare function requireWithTsconfigFallback<T = any>(filePath: string, tsConfigPath?: string): T;
|
|
29
118
|
/**
|
|
30
119
|
* Register ts-node or swc-node given a set of compiler options.
|
|
31
120
|
*
|