UNPKG

13.1 kBJavaScriptView Raw
1"use strict";
2/*
3 * @adonisjs/sink
4 *
5 * (c) Harminder Virk <virk@adonisjs.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11 if (k2 === undefined) k2 = k;
12 var desc = Object.getOwnPropertyDescriptor(m, k);
13 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14 desc = { enumerable: true, get: function() { return m[k]; } };
15 }
16 Object.defineProperty(o, k2, desc);
17}) : (function(o, m, k, k2) {
18 if (k2 === undefined) k2 = k;
19 o[k2] = m[k];
20}));
21var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22 Object.defineProperty(o, "default", { enumerable: true, value: v });
23}) : function(o, v) {
24 o["default"] = v;
25});
26var __importStar = (this && this.__importStar) || function (mod) {
27 if (mod && mod.__esModule) return mod;
28 var result = {};
29 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
30 __setModuleDefault(result, mod);
31 return result;
32};
33Object.defineProperty(exports, "__esModule", { value: true });
34exports.Instructions = void 0;
35const path_1 = require("path");
36const utils_1 = require("@poppinss/utils");
37const helpers_1 = require("@poppinss/utils/build/helpers");
38const sink = __importStar(require("../../../index"));
39const TemplatesManager_1 = require("../TemplatesManager");
40/**
41 * Exposes the API to execute the instructions of a package, defined inside
42 * the `package.json` file.
43 */
44class Instructions {
45 constructor(packageName, projectRoot, application, verbose = false) {
46 this.packageName = packageName;
47 this.projectRoot = projectRoot;
48 this.application = application;
49 this.verbose = verbose;
50 /**
51 * Path to the package package.json file
52 */
53 this.packagePath = this.getPackagePath();
54 this.markdownDisplay = undefined;
55 this.logger = sink.logger;
56 }
57 /**
58 * Formats object to string
59 */
60 formatObject(values) {
61 return Object.keys(values)
62 .map((key) => {
63 return `"${key} = ${values[key]}"`;
64 })
65 .join(',');
66 }
67 /**
68 * Formats array to string
69 */
70 formatArray(values) {
71 return values.map((v) => `"${v}"`).join(',');
72 }
73 /**
74 * Returns the suffix for the logger statements
75 */
76 getSuffix(value, key) {
77 if (!this.verbose) {
78 return '';
79 }
80 if (key) {
81 return this.logger.colors.yellow().dim(`{ ${key} += ${value} }`);
82 }
83 return this.logger.colors.yellow().dim(`{ ${value} }`);
84 }
85 /**
86 * Returns the absolute path to the package
87 */
88 getPackagePath() {
89 try {
90 return (0, helpers_1.resolveFrom)(this.projectRoot, `${this.packageName}/package.json`);
91 }
92 catch (error) {
93 if (['MODULE_NOT_FOUND', 'ENOENT'].includes(error.code)) {
94 throw new Error(`Cannot invoke instructions. Missing package "${this.packageName}"`);
95 }
96 throw error;
97 }
98 }
99 /**
100 * Load package json file from the package root directory
101 */
102 loadPackageJsonFile() {
103 return require(this.packagePath);
104 }
105 /**
106 * Copies templates to the user project
107 */
108 copyTemplates(instructions) {
109 if (!instructions.templates) {
110 return;
111 }
112 const templatesSourceDir = instructions.templates.basePath || './build/templates';
113 const templatesManager = new TemplatesManager_1.TemplatesManager(this.projectRoot, (0, path_1.join)((0, path_1.dirname)(this.packagePath), templatesSourceDir), this.application);
114 templatesManager.useLogger(this.logger).copy(instructions.templates);
115 }
116 /**
117 * Set environment variables
118 */
119 setEnvVariables(instructions) {
120 if (!instructions.env) {
121 return;
122 }
123 const envFile = new sink.files.EnvFile(this.projectRoot);
124 Object.keys(instructions.env).forEach((envKey) => envFile.set(envKey, instructions.env[envKey]));
125 envFile.commit();
126 const suffix = this.getSuffix(this.formatObject(instructions.env));
127 this.logger.action('update').succeeded(`.env ${suffix}`);
128 }
129 /**
130 * Adds the types to the tsconfig.json file
131 */
132 setTypes(instructions) {
133 if (!instructions.types) {
134 return;
135 }
136 const fileName = 'tsconfig.json';
137 const tsConfig = new sink.files.JsonFile(this.projectRoot, fileName);
138 const existingTypes = tsConfig.get('compilerOptions.types') || [];
139 /**
140 * Push type when doesn't exists already
141 */
142 if (!existingTypes.find((type) => type.includes(instructions.types))) {
143 existingTypes.push(instructions.types);
144 tsConfig.set('compilerOptions.types', existingTypes);
145 tsConfig.commit();
146 const suffix = this.getSuffix(this.formatArray([instructions.types]), 'types');
147 this.logger.action('update').succeeded(`${fileName} ${suffix}`);
148 }
149 }
150 /**
151 * Adds the meta files to `.adonisrc.json` file
152 */
153 setMetaFiles(instructions) {
154 if (!instructions.metaFiles) {
155 return;
156 }
157 const adonisRcFile = new sink.files.AdonisRcFile(this.projectRoot);
158 instructions.metaFiles.forEach((metaFile) => {
159 if (typeof metaFile === 'string') {
160 adonisRcFile.addMetaFile(metaFile);
161 }
162 else {
163 adonisRcFile.addMetaFile(metaFile.pattern, metaFile.reloadServer);
164 }
165 });
166 adonisRcFile.commit();
167 const suffix = this.getSuffix(this.formatArray(instructions.metaFiles.map((metaFile) => {
168 return typeof metaFile === 'string' ? metaFile : metaFile.pattern;
169 })), 'metaFiles');
170 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
171 }
172 /**
173 * Adds the preloads to `.adonisrc.json` file
174 */
175 setPreloads(instructions) {
176 if (!instructions.preloads) {
177 return;
178 }
179 const adonisRcFile = new sink.files.AdonisRcFile(this.projectRoot);
180 instructions.preloads.forEach((preloadFile) => {
181 if (typeof preloadFile === 'string') {
182 adonisRcFile.setPreload(preloadFile);
183 }
184 else {
185 adonisRcFile.setPreload(preloadFile.file, preloadFile.environment, preloadFile.optional);
186 }
187 });
188 adonisRcFile.commit();
189 const suffix = this.getSuffix(this.formatArray(instructions.preloads.map((preloadFile) => {
190 return typeof preloadFile === 'string' ? preloadFile : preloadFile.file;
191 })), 'preloads');
192 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
193 }
194 /**
195 * Set commands inside the adonisrc.json file
196 */
197 setCommands(instructions) {
198 if (!instructions.commands) {
199 return;
200 }
201 const adonisRcFile = new sink.files.AdonisRcFile(this.projectRoot);
202 instructions.commands.forEach((command) => adonisRcFile.addCommand(command));
203 adonisRcFile.commit();
204 const suffix = this.getSuffix(this.formatArray(instructions.commands), 'commands');
205 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
206 }
207 /**
208 * Set aliases inside the adonisrc.json file
209 */
210 setAliases(instructions) {
211 if (!instructions.aliases) {
212 return;
213 }
214 const adonisRcFile = new sink.files.AdonisRcFile(this.projectRoot);
215 const tsConfig = new sink.files.JsonFile(this.projectRoot, 'tsconfig.json');
216 const existingPaths = tsConfig.get('compilerOptions.paths') || {};
217 Object.keys(instructions.aliases).forEach((alias) => {
218 adonisRcFile.setAlias(alias, instructions.aliases[alias]);
219 existingPaths[`${alias}/*`] = [`${instructions.aliases[alias]}/*`];
220 });
221 const suffix = this.getSuffix(this.formatObject(instructions.aliases), 'aliases');
222 adonisRcFile.commit();
223 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
224 tsConfig.set('compilerOptions.paths', existingPaths);
225 tsConfig.commit();
226 this.logger.action('update').succeeded(`tsconfig.json ${suffix}`);
227 }
228 /**
229 * Sets providers or ace providers inside the `.adonisrc.json` file
230 */
231 setProviders(instructions) {
232 /**
233 * Return early when not providers are mentioned
234 */
235 if (!instructions.providers && !instructions.aceProviders && !instructions.testProviders) {
236 return;
237 }
238 const adonisRcFile = new sink.files.AdonisRcFile(this.projectRoot);
239 if (instructions.providers) {
240 instructions.providers.forEach((provider) => adonisRcFile.addProvider(provider));
241 }
242 if (instructions.aceProviders) {
243 instructions.aceProviders.forEach((provider) => adonisRcFile.addAceProvider(provider));
244 }
245 if (instructions.testProviders) {
246 instructions.testProviders.forEach((provider) => adonisRcFile.addTestProvider(provider));
247 }
248 adonisRcFile.commit();
249 if (instructions.providers) {
250 const suffix = this.getSuffix(this.formatArray(instructions.providers), 'providers');
251 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
252 }
253 if (instructions.aceProviders) {
254 const suffix = this.getSuffix(this.formatArray(instructions.aceProviders), 'aceProviders');
255 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
256 }
257 if (instructions.testProviders) {
258 const suffix = this.getSuffix(this.formatArray(instructions.testProviders), 'testProviders');
259 this.logger.action('update').succeeded(`.adonisrc.json ${suffix}`);
260 }
261 }
262 /**
263 * Executes the instructions fn exposed by the package inside package.json file.
264 */
265 async runInstructions(instructions) {
266 if (!instructions.instructions) {
267 return;
268 }
269 /**
270 * Path to the instructions file is resolved from the package root.
271 */
272 const instructionsPath = (0, helpers_1.resolveFrom)((0, path_1.dirname)(this.packagePath), instructions.instructions);
273 /**
274 * Requiring and executing instructions file
275 */
276 const instructionsFn = (0, utils_1.esmRequire)(instructionsPath);
277 await instructionsFn(this.projectRoot, this.application, {
278 ...sink,
279 logger: this.logger,
280 });
281 }
282 /**
283 * Renders the markdown file if defined inside the package.json file.
284 */
285 async renderMarkdownFile(instructions) {
286 if (!instructions.instructionsMd || !this.verbose) {
287 return;
288 }
289 if (!this.markdownDisplay) {
290 this.logger.info('The package wants to display readable instructions for the setup');
291 this.markdownDisplay = await sink.getPrompt().choice('Select where to display instructions', [
292 {
293 name: 'browser',
294 message: 'In the browser',
295 },
296 {
297 name: 'terminal',
298 message: 'In the terminal',
299 },
300 ]);
301 }
302 /**
303 * Render markdown file when `instructionsMd` property is defined in
304 * package.json file
305 */
306 const renderer = new sink.tasks.MarkdownRenderer((0, path_1.join)((0, path_1.dirname)(this.packagePath), instructions.instructionsMd), this.packageName);
307 if (this.markdownDisplay === 'browser') {
308 renderer.renderInBrowser();
309 }
310 else {
311 console.log('');
312 renderer.renderInTerminal();
313 }
314 }
315 /**
316 * Preset markdown display for avoiding prompt
317 */
318 setDisplay(display) {
319 this.markdownDisplay = display;
320 return this;
321 }
322 /**
323 * Define a custom logger to use
324 */
325 useLogger(logger) {
326 this.logger = logger;
327 return this;
328 }
329 /**
330 * Execute the instructions file
331 */
332 async execute() {
333 const pkg = this.loadPackageJsonFile();
334 if (!pkg.adonisjs) {
335 return true;
336 }
337 await this.runInstructions(pkg.adonisjs);
338 this.copyTemplates(pkg.adonisjs);
339 this.setEnvVariables(pkg.adonisjs);
340 this.setTypes(pkg.adonisjs);
341 this.setCommands(pkg.adonisjs);
342 this.setAliases(pkg.adonisjs);
343 this.setProviders(pkg.adonisjs);
344 this.setMetaFiles(pkg.adonisjs);
345 this.setPreloads(pkg.adonisjs);
346 await this.renderMarkdownFile(pkg.adonisjs);
347 return true;
348 }
349}
350exports.Instructions = Instructions;