{"id":13748903,"url":"https://github.com/tidev/appc-tasks","last_synced_at":"2025-11-01T18:30:23.985Z","repository":{"id":36985373,"uuid":"98311753","full_name":"tidev/appc-tasks","owner":"tidev","description":"Provides an extendable base interface for file based build tasks","archived":false,"fork":false,"pushed_at":"2024-03-05T09:24:31.000Z","size":2093,"stargazers_count":6,"open_issues_count":26,"forks_count":2,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-10-15T07:30:58.467Z","etag":null,"topics":["npm-package"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tidev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"tidev","liberapay":"tidev"}},"created_at":"2017-07-25T13:53:27.000Z","updated_at":"2023-01-31T16:51:30.000Z","dependencies_parsed_at":"2024-08-03T07:12:37.423Z","dependency_job_id":null,"html_url":"https://github.com/tidev/appc-tasks","commit_stats":null,"previous_names":["appcelerator/appc-tasks"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidev%2Fappc-tasks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidev%2Fappc-tasks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidev%2Fappc-tasks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidev%2Fappc-tasks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tidev","download_url":"https://codeload.github.com/tidev/appc-tasks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239311608,"owners_count":19618013,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["npm-package"],"created_at":"2024-08-03T07:00:52.023Z","updated_at":"2025-11-01T18:30:23.947Z","avatar_url":"https://github.com/tidev.png","language":"JavaScript","funding_links":["https://github.com/sponsors/tidev","https://liberapay.com/tidev"],"categories":["JavaScript"],"sub_categories":[],"readme":"# appc-tasks\n\n[![Travis Build Status](https://travis-ci.org/appcelerator/appc-tasks.svg?branch=master)](https://travis-ci.org/appcelerator/appc-tasks)\n[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/edxjipwjl9qxtfc9?svg=true)](https://ci.appveyor.com/project/appcelerator/appc-tasks)\n[![Coverage Status](https://coveralls.io/repos/github/appcelerator/appc-tasks/badge.svg?branch=master)](https://coveralls.io/github/appcelerator/appc-tasks?branch=master)\n[![Dependencies](https://david-dm.org/appcelerator/appc-tasks.svg)](https://david-dm.org/appcelerator/appc-tasks) [![Greenkeeper badge](https://badges.greenkeeper.io/appcelerator/appc-tasks.svg)](https://greenkeeper.io/)\n\n\u003e Base implementations for any kind of task in NodeJS\n\n## Introduction\n\nThis module provides base implementations that can be used to create your own tasks. A task in this context represents some atomic piece of work. It is used within the Titanium SDK and Hyperloop build pipelines but is designed to be usable in any other project as well.\n\nA full API documentation can be found at http://appcelerator.github.io/appc-tasks/?api\n\n## Getting started\n\nInstall via npm\n\n```bash\nnpm i appc-tasks -S\n```\n\nand create your own tasks using the provided base implementation\n\n```javascript\nimport { BaseTask } from 'appc-tasks';\n\nclass MyTask extends BaseTask {\n  runTaskAction() {\n    // Implement task logic here\n  }\n}\n\nlet task = new MyTask({name: 'myTask'});\ntask.run().then(() =\u003e {\n  console.log('Task completed');\n}).catch(err =\u003e {\n  console.log(`Task failed with error: ${err}`);\n});\n```\n\n### The base task\n\nAll tasks extend from the `BaseTask` class which defines the interface how tasks are being run. New tasks that extend from the `BaseTask` need to override `runTaskAction` and define their task action there. To  customize the behavior of a task, you can also implement the `beforeTaskAction` and `afterTaskAction` methods which will automatically be called by the task's `run` method. Here you can do any pre- or post-processing that might be required for every instance of that specific task. In addition a task instance can be assigned a `preTaskRun` and `postTaskRun` function, which is intended to further customize a single instance of your task.\n\n```javascript\nimport { BaseTask } from 'appc-tasks';\n\nclass CustomTask extends BaseTask {\n  beforeTaskAction() {\n    this.logger.debug('beforeTaskAction');\n  }\n\n  runTaskAction() {\n    this.logger.debug('runTaskAction');\n  }\n\n  afterTaskAction() {\n    this.logger.debug('afterTaskAction');\n  }\n}\n\nlet task = new CustomTask({\n  name: 'customTask';\n});\ntaskInstance.preTaskRun = () =\u003e {\n  task.logger.debug('preTaskRun');\n}\ntaskInstance.postTaskRun = () =\u003e {\n  task.logger.info('postTaskRun');\n}\ntaskInstance.run();\n// log output:\n// customTask: preTaskRun\n// customTask: beforeTaskAction\n// customTask: runTaskAction\n// customTask: afterTaskAction\n// customTask: postTaskRun\n```\n\nAll of the above methods are executed in a `.then` chain, allowing you to perform async operations by returning a `Promise`.\n\nThe base constructor can receive two options, a required `name` and and an optional `logger`. If you don't provide a logger, a default logger using `console.log` will be created. In the event that you want to provide your own logger, it has to be compatible to bunyan's [log method API](https://github.com/trentm/node-bunyan#log-method-api). A task will wrap the passed logger in an adapter, which will prefix every log message with the task name for better readability throughout all your tasks log messages.\n\n\u003e ✅ Always assign a unique name to a task, whereby it can be properly identified.\n\n### File based tasks\n\nThe `BaseFileTask` extends the `BaseTask` with the concept of input and output files. Tasks that implement this interface can use that to describe which input files they require and which output files they will produce.\n\n```javascript\nimport { BaseFileTask } from 'appc-tasks';\n\nclass FileTask extends BaseFileTask {\n\n  constructor(taskInfo) {\n    super(taskInfo);\n\n    this._sourceDirectory = null;\n    this._outputDirectory = null;\n  }\n\n  get sourceDirectory() {\n    return this._sourceDirectory;\n  }\n\n  set sourceDirectory(sourceDirectory) {\n    this._sourceDirectory = sourceDirectory;\n    this.addInputDirectory(this.sourceDirectory);\n  }\n\n  get outputDirectory() {\n    return this._outputDirectory;\n  }\n\n  set outputDirectory(outputPath) {\n    this._outputDirectory = outputPath;\n    this.registerOutputPath(this.outputDirectory);\n  }\n\n  runTaskAction() {\n    // this.inputFiles contains every file under the source directory\n    for (let inputFile of this.inputFiles) {\n      // Do your stuff, e.g. process inputFiles and write them to outputDirectory\n    }\n  }\n}\n\nlet task = new FileTask({\n  name: 'fileTask'\n});\ntask.sourceDirectory = '/path/to/some/sources';\ntask.outputDirectory = '/path/to/output';\ntask.run();\n```\n\nIn the above example, adding of input files is masked behind setting a property for a cleaner API. You can also pass `inputFiles` directly via a the constructor option of the same name if you know your set of input files beforehand, or manually call the `addInputFile` and `addInputDirectory` methods.\n\nSimilar to the input files, you can also define output files and directories. Do so by calling `registerOutputPath`, which will register the path so the task knows where to search for generated output files. The `BaseFileTask.afterTaskAction` implementation will recursively scan your registered output paths and add all found files to the `outputFiles` property after the task finished its `runTaskAction`.\n\n\u003e ⚠️ Do not call `addOutputFile` or `addOutputDirectory` yourself, the `afterTaskAction` will do this for you using the registered output paths.\n\n\u003e ✅ Handle the adding of input files and registration of output paths behind a property setters for a clean API in your task. This also allows you to easily access the paths using fitting property names.\n\n### Incremental file tasks\n\nThe `IncrementalFileTask` further extends the `BaseFileTask` with the ability to run full and incremental task actions, depending on wether input or output files changed. There are a few slight changes in the implementation when creating a custom incremental task.\n\n```javascript\nimport { IncrementalFileTask } from 'appc-tasks';\n\nclass MySmartTask extends IncrementalFileTask {\n  get incrementalOutputs() {\n    return [this.outputDirectory];\n  }\n\n  get outputDirectory() {\n    return this._outputDirectory;\n  }\n\n  set outputDirectory(outputPath) {\n    this._outputDirectory = outputPath;\n    this.registerOutputPath(this.outputDirectory);\n  }\n\n  doFullTaskRun() {\n    // Implement your full task run action here\n  }\n\n  doIncrementalTaskRun(changedFiles) {\n    // Implement your incremental task run action here\n  }\n}\n\nlet task = new MySmartTask({\n  name: 'incrementalTask',\n  incrementalDirectory: '/incremental/mytask'\n});\ntask.addInputDirectory('/input/path');\ntask.outputDirectory = '/output/path';\ntask.run();\n```\n\nWhen creating a new incremental task instance, the constructor requires a `incrementalDirectory` to be passed via the options object. This directory will hold all the state data that is used to determine changed files and any other data your task might require to perform its incremental action.\n\nThe `incrementalOutputs` getter is used to define the output files and directories that will be checked to see if a anything changed and trigger a full run. This has to be an Array of paths you are free to set as you seem fit for your task. By default it is an empty array.\n\nInstead of overriding `runTaskAction` like in the previous examples, incremental tasks need to override `doFullTaskRun` and `doIncrementalTaskRun` to define the its logic. `runTaskAction` already handles the detection of file changes and triggers either a full or incremental task run. The rules for this are:\n\n* No incremental data: full task run\n* Output files changed: full task run\n* Input files changed: incremental task run\n* Nothing changed: skip task run\n\nThe `changedFiles` in `doIncrementalTaskRun` will be a `Map` with the full path to the file as the key, and either the string `created`, `changed` or `deleted` as the value.\n\n## What's next?\n\n- [ ] Ability to organize tasks into some sort of Project and define dependencies between those tasks. The project then manages the execution of all tasks, taking care of execution order as well as passing input and output data from and to the individual tasks.\n- [ ] Make use of ES7 decorators to mark properties as inputs and outputs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidev%2Fappc-tasks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftidev%2Fappc-tasks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidev%2Fappc-tasks/lists"}