wp-advads 1.0.31 → 1.0.34
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/.github/workflows/test.yml +17 -0
- package/CHANGELOG.md +23 -1
- package/LICENSE +15 -0
- package/README.md +8 -7
- package/package.json +9 -7
- package/src/app.js +17 -11
- package/src/commands/build.js +72 -59
- package/src/commands/class.js +34 -40
- package/src/commands/css.js +13 -19
- package/src/commands/init.js +4 -1
- package/src/commands/javascript.js +13 -19
- package/src/commands/release/change-version.js +14 -17
- package/src/commands/release/changelog.js +23 -31
- package/src/commands/release/git.js +25 -13
- package/src/commands/release/github.js +63 -12
- package/src/commands/release/semver.js +22 -25
- package/src/commands/release/translations.js +17 -23
- package/src/commands/release.js +3 -4
- package/src/commands/updates.js +20 -17
- package/src/commands/views.js +16 -18
- package/src/commands/wp-glotpress.js +125 -126
- package/src/commands/wp-pot.js +17 -9
- package/src/utilities/filesystem.js +57 -36
- package/src/utilities/flow.js +21 -0
- package/src/utilities/formatting.js +13 -4
- package/src/utilities/index.js +1 -1
- package/src/utilities/misc.js +1 -6
- package/src/utilities/settings.js +34 -14
- package/src/utilities/shell.js +60 -8
- package/template/files/class-singleton.php +5 -0
- package/template/files/javascript.js +0 -2
- package/template/files/view.php +2 -0
- package/test/build.test.js +168 -0
- package/test/changelog-locales.test.js +49 -0
- package/test/class.test.js +47 -0
- package/test/compile-templates.test.js +70 -0
- package/test/deps-hygiene.test.js +46 -0
- package/test/engines.test.js +11 -0
- package/test/get-latest-tag.test.js +51 -0
- package/test/git-precheck.test.js +44 -0
- package/test/github-final.test.js +93 -0
- package/test/glotpress-download.test.js +176 -0
- package/test/nested-path.test.js +39 -0
- package/test/no-fs-extra.test.js +11 -0
- package/test/package-identity.test.js +19 -0
- package/test/path-confine.test.js +42 -0
- package/test/pot-docs.test.js +27 -0
- package/test/pot-headers.test.js +49 -0
- package/test/project-root.test.js +26 -0
- package/test/release-waterfall.test.js +62 -0
- package/test/semver.test.js +25 -0
- package/test/settings-clone.test.js +34 -0
- package/test/settings-path.test.js +31 -0
- package/test/shell.test.js +100 -0
- package/test/singleton.test.js +14 -0
- package/test/stable-tag.test.js +13 -0
- package/test/stub-security.test.js +37 -0
- package/test/template-folder.test.js +19 -0
- package/test/translations.test.js +51 -0
- package/test/update-file-content.test.js +38 -0
- package/test/updates.test.js +39 -0
- package/test/version.test.js +22 -0
- package/test/view-escape.test.js +17 -0
- package/test/view.test.js +33 -0
- package/test/write-force.test.js +47 -0
- package/src/utilities/semver.js +0 -45
- package/template/.github/pull_request_template.md +0 -52
- package/template/configs/.editorconfig +0 -27
- package/template/configs/.eslintignore +0 -13
- package/template/configs/.eslintrc.js +0 -13
- package/template/configs/.phpcs.xml.dist +0 -87
- package/template/configs/.prettierignore +0 -49
- package/template/configs/.prettierrc.js +0 -3
- package/template/configs/.stylelintrc +0 -44
- package/template/configs/composer.json +0 -51
- package/template/configs/gitattributes +0 -34
- package/template/configs/gitignore +0 -43
- package/template/configs/package.json +0 -66
- package/template/configs/postcss.config.js +0 -6
- package/template/configs/tailwind.config.js +0 -8
- package/template/configs/webpack.mix.js +0 -65
- package/template/configs/webpack.mix.local.js +0 -3
- package/template/includes/index.php +0 -2
- package/template/index.js +0 -0
- package/template/index.php +0 -4
- package/template/plugin/assets/scss/app.scss +0 -0
- package/template/plugin/assets/src/app.js +0 -0
- package/template/tools/laravel-mix/wp-pot.js +0 -57
- package/template/tools/wp-glotpress.js +0 -162
|
@@ -4,163 +4,162 @@
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { resolve } from 'path';
|
|
7
|
-
import eachSeries from 'async/eachSeries.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Internal Dependencies
|
|
11
|
-
*/
|
|
12
7
|
import { heading, msgError, getSetting, write, msgSuccessOnSameLine, onSameLine, msgErrorOnSameLine } from "../utilities/index.js";
|
|
13
8
|
|
|
14
|
-
|
|
15
|
-
baseURL = 'https://translate.wpadvancedads.com/api/projects';
|
|
9
|
+
const BASE_URL = 'https://translate.wpadvancedads.com/api/projects';
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
export async function downloadTranslations() {
|
|
12
|
+
heading('Downloading Translations from GlotPress...')
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
14
|
+
try {
|
|
15
|
+
const ctx = readProject();
|
|
16
|
+
ensureDestination( ctx.destination );
|
|
17
|
+
return await downloadAll( ctx );
|
|
18
|
+
} catch (error) {
|
|
19
|
+
msgError(error.message);
|
|
20
|
+
throw error;
|
|
28
21
|
}
|
|
22
|
+
}
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
export default () => {
|
|
25
|
+
downloadTranslations().catch(() => {});
|
|
26
|
+
}
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
28
|
+
function readProject() {
|
|
29
|
+
const glotpress = getSetting('glotpress')
|
|
30
|
+
write('Validating data...');
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
if (!glotpress) {
|
|
33
|
+
onSameLine('')
|
|
34
|
+
throw new Error('No glotpress project found');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if ('' === glotpress.project) {
|
|
38
|
+
throw new Error('The GlotPress project name is not defined.');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (undefined === glotpress.destination || '' === glotpress.destination) {
|
|
42
|
+
throw new Error('The destination directory is not defined.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { project, destination } = glotpress;
|
|
46
|
+
const domain = getSetting('wpPot.domain');
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
msgSuccessOnSameLine('Validation done');
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
project,
|
|
52
|
+
potPrefix: domain ?? project,
|
|
53
|
+
destination,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
function ensureDestination( destination ) {
|
|
58
|
+
write('Checking if destination directory exists...');
|
|
59
|
+
fs.mkdirSync(resolve(destination), { recursive: true });
|
|
60
|
+
msgSuccessOnSameLine('Directory exists');
|
|
61
|
+
}
|
|
50
62
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
async function downloadAll( ctx ) {
|
|
64
|
+
const locales = await getLocales( ctx );
|
|
65
|
+
if (false === locales) {
|
|
66
|
+
return { files: [], locales: {} };
|
|
67
|
+
}
|
|
54
68
|
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
const files = [];
|
|
70
|
+
const names = {};
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
write('Checking if destination directory exists...');
|
|
72
|
+
for ( const locale of Object.keys( locales ) ) {
|
|
73
|
+
const set = locales[ locale ];
|
|
61
74
|
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
console.log( '' );
|
|
76
|
+
console.log(
|
|
77
|
+
chalk.yellow.bold( 'Updating Language:' ) +
|
|
78
|
+
` ${chalk.italic( set.name )}`
|
|
79
|
+
);
|
|
64
80
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
for ( const format of [ 'mo', 'po' ] ) {
|
|
82
|
+
const target = await downloadFile( ctx, locale, set, format );
|
|
83
|
+
if ( target ) {
|
|
84
|
+
const file = target.replace( /^\.\//, '' );
|
|
85
|
+
files.push( file );
|
|
86
|
+
names[ file ] = set.name;
|
|
69
87
|
}
|
|
70
|
-
} else {
|
|
71
|
-
msgSuccessOnSameLine('Directory exists');
|
|
72
88
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async download() {
|
|
76
|
-
const locales = await this.getLocales();
|
|
77
|
-
if (false === locales) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
eachSeries(
|
|
82
|
-
Object.keys(locales),
|
|
83
|
-
(locale, callback) => {
|
|
84
|
-
const set = locales[locale];
|
|
85
|
-
|
|
86
|
-
console.log('');
|
|
87
|
-
console.log(
|
|
88
|
-
chalk.yellow.bold('Updating Language:') +
|
|
89
|
-
` ${chalk.italic(set.name)}`
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
eachSeries(['mo', 'po'], (format, nextFormat) => {
|
|
93
|
-
this.downloadFile(locale, set, format, nextFormat);
|
|
94
|
-
}, (err) => {
|
|
95
|
-
callback();
|
|
96
|
-
})
|
|
97
|
-
},
|
|
98
|
-
(err, results) => {
|
|
99
|
-
if (err) {
|
|
100
|
-
msgError(err.message);
|
|
101
|
-
} else {
|
|
102
|
-
console.log('');
|
|
103
|
-
console.log(
|
|
104
|
-
chalk.bgGreen.bold('Success:') +
|
|
105
|
-
' All files has been downloaded.'
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
)
|
|
110
89
|
}
|
|
111
90
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
91
|
+
console.log( '' );
|
|
92
|
+
console.log(
|
|
93
|
+
chalk.bgGreen.bold( 'Success:' ) +
|
|
94
|
+
' All files has been downloaded.'
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return { files, locales: names };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function getLocales( ctx ) {
|
|
101
|
+
write('Downloading locales...');
|
|
102
|
+
const response = await fetch(`${BASE_URL}/${ctx.project}`, {
|
|
103
|
+
signal: AbortSignal.timeout(30000),
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
msgErrorOnSameLine(`HTTP ${response.status}`);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const data = await response.json();
|
|
110
|
+
const sets = {};
|
|
111
|
+
|
|
112
|
+
if (undefined !== data.success && !data.success) {
|
|
113
|
+
msgErrorOnSameLine(data.error);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
data.translation_sets.map((set) => {
|
|
118
|
+
if (set.current_count > 0) {
|
|
119
|
+
let id = set.wp_locale;
|
|
120
|
+
if ('default' !== set.slug) {
|
|
121
|
+
id += '_' + set.slug;
|
|
122
|
+
}
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
let id = set.wp_locale;
|
|
126
|
-
if ('default' !== set.slug) {
|
|
127
|
-
id += '_' + set.slug;
|
|
128
|
-
}
|
|
124
|
+
sets[id] = set;
|
|
125
|
+
}
|
|
129
126
|
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
return false;
|
|
128
|
+
});
|
|
132
129
|
|
|
133
|
-
|
|
134
|
-
});
|
|
130
|
+
msgSuccessOnSameLine('Downloaded locales');
|
|
135
131
|
|
|
136
|
-
|
|
132
|
+
return sets;
|
|
133
|
+
}
|
|
137
134
|
|
|
138
|
-
|
|
135
|
+
async function downloadFile(ctx, locale, data, format) {
|
|
136
|
+
if (!/^[a-zA-Z0-9_]+$/.test(locale)) {
|
|
137
|
+
msgErrorOnSameLine(`Skipping invalid locale: ${locale}`);
|
|
138
|
+
return;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
);
|
|
141
|
+
write(
|
|
142
|
+
chalk.bold(`Downloading: ${ctx.potPrefix}-${locale}.${format}`)
|
|
143
|
+
);
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
const target = `${ctx.destination}/${ctx.potPrefix}-${locale}.${format}`;
|
|
146
|
+
const endpoint = `${BASE_URL}/${ctx.project}/${data.locale}/${data.slug}/export-translations?format=${format}`;
|
|
148
147
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
const response = await fetch(endpoint, {
|
|
149
|
+
signal: AbortSignal.timeout(30000),
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
msgErrorOnSameLine(`Skipping ${ctx.potPrefix}-${locale}.${format}`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
152
155
|
|
|
153
|
-
|
|
156
|
+
const content = await response.text();
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
chalk.bold(`Downloaded: ${this.potPrefix}-${locale}.${format}`)
|
|
157
|
-
);
|
|
158
|
+
fs.writeFileSync(target, content);
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
onSameLine(
|
|
161
|
+
chalk.bold(`Downloaded: ${ctx.potPrefix}-${locale}.${format}`)
|
|
162
|
+
);
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
const downloader = new GlotPressDownloader();
|
|
165
|
-
downloader.run();
|
|
164
|
+
return target;
|
|
166
165
|
}
|
package/src/commands/wp-pot.js
CHANGED
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
import { heading, msgSuccess, runCommand, getSetting } from "../utilities/index.js"
|
|
5
5
|
|
|
6
6
|
export default (next = null) => {
|
|
7
|
-
heading('Generating
|
|
7
|
+
heading('Generating POT file...')
|
|
8
8
|
|
|
9
9
|
const settings = getSetting()
|
|
10
10
|
|
|
11
11
|
const output = settings.wpPot.output;
|
|
12
12
|
const file = settings.wpPot.file;
|
|
13
13
|
const domain = settings.wpPot.domain;
|
|
14
|
+
const name = settings.author?.name ?? ''
|
|
15
|
+
const email = settings.author?.email ?? ''
|
|
14
16
|
const headers = {
|
|
15
|
-
'Last-Translator':
|
|
16
|
-
'Language-Team':
|
|
17
|
+
'Last-Translator': `${name} <${email}>`,
|
|
18
|
+
'Language-Team': `${name} <${email}>`,
|
|
17
19
|
};
|
|
18
20
|
const exclude = [
|
|
19
21
|
'.git',
|
|
@@ -28,17 +30,23 @@ export default (next = null) => {
|
|
|
28
30
|
|
|
29
31
|
// Execute.
|
|
30
32
|
const rootPath = process.cwd();
|
|
31
|
-
|
|
32
|
-
'
|
|
33
|
+
runCommand( 'wp', [
|
|
34
|
+
'i18n',
|
|
35
|
+
'make-pot',
|
|
33
36
|
rootPath,
|
|
34
37
|
rootPath + output + file,
|
|
35
38
|
`--domain=${domain}`,
|
|
36
39
|
`--exclude=${exclude.join(',')}`,
|
|
37
|
-
`--headers
|
|
38
|
-
]
|
|
40
|
+
`--headers=${JSON.stringify(headers)}`,
|
|
41
|
+
], ( error ) => {
|
|
42
|
+
if ( error ) {
|
|
43
|
+
if ( next ) {
|
|
44
|
+
next( error )
|
|
45
|
+
}
|
|
46
|
+
return
|
|
47
|
+
}
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
msgSuccess('PO and MO files generated successfully');
|
|
49
|
+
msgSuccess('POT file generated successfully');
|
|
42
50
|
if (next) next();
|
|
43
51
|
} );
|
|
44
52
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import chalk from 'chalk';
|
|
5
4
|
import logSymbols from 'log-symbols';
|
|
6
5
|
import template from 'lodash/template.js';
|
|
7
6
|
|
|
@@ -9,12 +8,13 @@ import template from 'lodash/template.js';
|
|
|
9
8
|
* Node dependencies
|
|
10
9
|
*/
|
|
11
10
|
import path from 'path';
|
|
12
|
-
import fs from 'fs
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Internal Dependencies
|
|
16
16
|
*/
|
|
17
|
-
import { msgSuccessOnSameLine, onSameLine, write } from './formatting.js'
|
|
17
|
+
import { msgErrorTitle, msgSuccessOnSameLine, onSameLine, write } from './formatting.js'
|
|
18
18
|
|
|
19
19
|
let projectRoot = null
|
|
20
20
|
|
|
@@ -32,32 +32,26 @@ export function getProjectRoot(startDir = process.cwd()) {
|
|
|
32
32
|
return projectRoot;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
let dir = startDir;
|
|
36
36
|
|
|
37
|
-
while (
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
while (dir !== path.parse(dir).root) {
|
|
38
|
+
if (fs.existsSync(path.join(dir, 'wp.advads'))) {
|
|
39
|
+
projectRoot = dir;
|
|
40
40
|
return projectRoot;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
43
|
+
dir = path.dirname(dir);
|
|
44
|
+
}
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
projectRoot = null;
|
|
47
|
+
throw new Error('Project root not found. Make sure there is a wp.advads file in the root directory.');
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* Retrieves the path to the template folder.
|
|
52
|
-
*
|
|
53
|
-
* This function uses `createRequire` to resolve the path to the `../../template` directory
|
|
54
|
-
* relative to the current module's URL and removes the `/index.js` part from the resolved path.
|
|
55
|
-
*
|
|
56
51
|
* @returns {string} The path to the template folder.
|
|
57
52
|
*/
|
|
58
53
|
export function getTemplateFolder() {
|
|
59
|
-
|
|
60
|
-
return path.join(dirname, '../../template')
|
|
54
|
+
return path.join( path.dirname( fileURLToPath( import.meta.url ) ), '../../template' )
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
/**
|
|
@@ -87,21 +81,22 @@ export function compileTemplate( filename, data ) {
|
|
|
87
81
|
}
|
|
88
82
|
|
|
89
83
|
/**
|
|
90
|
-
*
|
|
84
|
+
* Compile a template and write it, or print the shared scaffold failure.
|
|
91
85
|
*
|
|
92
|
-
* @param {string}
|
|
93
|
-
* @param {string}
|
|
94
|
-
*
|
|
95
|
-
* @
|
|
86
|
+
* @param {string} folder
|
|
87
|
+
* @param {string} filename
|
|
88
|
+
* @param {string} templateFile Path under template/
|
|
89
|
+
* @param {Object} data
|
|
90
|
+
* @param {boolean} force
|
|
96
91
|
*/
|
|
97
|
-
export function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
export function writeFromTemplate( folder, filename, templateFile, data, force = false ) {
|
|
93
|
+
try {
|
|
94
|
+
const content = compileTemplate( getTemplateFile( templateFile ), data )
|
|
95
|
+
writeFile( folder, filename, content, force )
|
|
96
|
+
} catch ( err ) {
|
|
97
|
+
msgErrorTitle( 'We failed!!!' )
|
|
98
|
+
throw err
|
|
99
|
+
}
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
/**
|
|
@@ -120,7 +115,7 @@ export function updateFileContent(fileName, messages, next, callback) {
|
|
|
120
115
|
fs.readFile(fileName, (err, buffer) => {
|
|
121
116
|
if ( null !== err ) {
|
|
122
117
|
onSameLine(`${logSymbols.error} ${messages.failed}`)
|
|
123
|
-
return next()
|
|
118
|
+
return next(err)
|
|
124
119
|
}
|
|
125
120
|
|
|
126
121
|
const content = callback(buffer.toString())
|
|
@@ -128,7 +123,7 @@ export function updateFileContent(fileName, messages, next, callback) {
|
|
|
128
123
|
fs.writeFile(fileName, content, (err) => {
|
|
129
124
|
if ( null !== err ) {
|
|
130
125
|
onSameLine(`${logSymbols.error} ${messages.failed}`)
|
|
131
|
-
return next()
|
|
126
|
+
return next(err)
|
|
132
127
|
}
|
|
133
128
|
|
|
134
129
|
onSameLine(`${logSymbols.success} ${messages.updated}`)
|
|
@@ -137,12 +132,38 @@ export function updateFileContent(fileName, messages, next, callback) {
|
|
|
137
132
|
})
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
|
|
135
|
+
function assertInsideProject( target ) {
|
|
136
|
+
if ( String( target ).includes( '\0' ) ) {
|
|
137
|
+
throw new Error( 'Invalid path' )
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const root = path.resolve( getProjectRoot() )
|
|
141
|
+
const resolved = path.resolve( target )
|
|
142
|
+
const relative = path.relative( root, resolved )
|
|
143
|
+
|
|
144
|
+
if ( relative.startsWith( `..${path.sep}` ) || relative === '..' || path.isAbsolute( relative ) ) {
|
|
145
|
+
throw new Error( 'Path escapes project root' )
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function writeFile(folder, filename, content, force = false) {
|
|
150
|
+
if ( String( filename ).includes( '\0' ) ) {
|
|
151
|
+
throw new Error( 'Invalid path' )
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
assertInsideProject( folder )
|
|
155
|
+
assertInsideProject( path.join( folder, filename ) )
|
|
156
|
+
|
|
157
|
+
const target = path.join( folder, filename )
|
|
158
|
+
if ( ! force && fs.existsSync( target ) ) {
|
|
159
|
+
throw new Error( `File exists: ${target}` )
|
|
160
|
+
}
|
|
161
|
+
|
|
141
162
|
write('Creating directories!!');
|
|
142
|
-
fs.
|
|
163
|
+
fs.mkdirSync(folder, { recursive: true });
|
|
143
164
|
msgSuccessOnSameLine('Directories created successfully');
|
|
144
165
|
|
|
145
166
|
write('Creating file!!');
|
|
146
|
-
fs.writeFileSync(
|
|
167
|
+
fs.writeFileSync(target, content);
|
|
147
168
|
msgSuccessOnSameLine('File created successfully');
|
|
148
169
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run callback-style steps in order. `next(err)` if any step fails.
|
|
3
|
+
*
|
|
4
|
+
* @param {Function[]} steps Each step is `(done) => void`
|
|
5
|
+
* @param {Function} next
|
|
6
|
+
*/
|
|
7
|
+
export function runSteps( steps, next ) {
|
|
8
|
+
;( async () => {
|
|
9
|
+
for ( const step of steps ) {
|
|
10
|
+
await new Promise( ( resolve, reject ) => {
|
|
11
|
+
step( ( err ) => {
|
|
12
|
+
if ( err ) {
|
|
13
|
+
reject( err )
|
|
14
|
+
} else {
|
|
15
|
+
resolve()
|
|
16
|
+
}
|
|
17
|
+
} )
|
|
18
|
+
} )
|
|
19
|
+
}
|
|
20
|
+
} )().then( () => next() ).catch( ( err ) => next( err ) )
|
|
21
|
+
}
|
|
@@ -28,6 +28,10 @@ export function onNewLine(text) {
|
|
|
28
28
|
console.log(text)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function canRewriteStdout() {
|
|
32
|
+
return Boolean( process.stdout.isTTY && ! process.env.NODE_TEST_CONTEXT )
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
/**
|
|
32
36
|
* Print text on same line by clearing buffer.
|
|
33
37
|
*
|
|
@@ -36,9 +40,9 @@ export function onNewLine(text) {
|
|
|
36
40
|
* @returns {void}
|
|
37
41
|
*/
|
|
38
42
|
export function onSameLine(text) {
|
|
39
|
-
if (process.stdout.clearLine) {
|
|
40
|
-
process.stdout.clearLine();
|
|
41
|
-
process.stdout.cursorTo(0);
|
|
43
|
+
if ( canRewriteStdout() && process.stdout.clearLine ) {
|
|
44
|
+
process.stdout.clearLine();
|
|
45
|
+
process.stdout.cursorTo(0);
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
console.log(text)
|
|
@@ -118,5 +122,10 @@ export function msgErrorTitle(msg) {
|
|
|
118
122
|
* @returns {void}
|
|
119
123
|
*/
|
|
120
124
|
export function write(text) {
|
|
121
|
-
|
|
125
|
+
if ( canRewriteStdout() ) {
|
|
126
|
+
process.stdout.write(text)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(text)
|
|
122
131
|
}
|
package/src/utilities/index.js
CHANGED
package/src/utilities/misc.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External Dependencies
|
|
3
|
-
*/
|
|
4
|
-
import capitalize from 'lodash/capitalize.js';
|
|
5
|
-
|
|
6
1
|
export function filenameToHeading(filename) {
|
|
7
2
|
filename = filename.replace('.php', '');
|
|
8
3
|
filename = filename.replace('.js', '');
|
|
9
4
|
filename = filename.replace(/-/g, ' ');
|
|
10
5
|
|
|
11
|
-
return
|
|
6
|
+
return filename.charAt(0).toUpperCase() + filename.slice(1).toLowerCase();
|
|
12
7
|
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import get from 'lodash/get.js'
|
|
5
|
-
import set from 'lodash/set.js'
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* Node dependencies
|
|
9
3
|
*/
|
|
@@ -18,6 +12,14 @@ import { write } from './formatting.js'
|
|
|
18
12
|
|
|
19
13
|
let settings = null
|
|
20
14
|
|
|
15
|
+
function configPath() {
|
|
16
|
+
try {
|
|
17
|
+
return path.join( getProjectRoot(), 'wp.advads' )
|
|
18
|
+
} catch {
|
|
19
|
+
return path.join( process.cwd(), 'wp.advads' )
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* Checks if the configuration file exists at the specified path.
|
|
23
25
|
*
|
|
@@ -25,8 +27,7 @@ let settings = null
|
|
|
25
27
|
*/
|
|
26
28
|
export function configFileExists() {
|
|
27
29
|
try {
|
|
28
|
-
|
|
29
|
-
return fs.existsSync(configPath);
|
|
30
|
+
return fs.existsSync( configPath() );
|
|
30
31
|
} catch (err) {
|
|
31
32
|
return false;
|
|
32
33
|
}
|
|
@@ -39,8 +40,7 @@ export function configFileExists() {
|
|
|
39
40
|
*/
|
|
40
41
|
export function readConfigFile() {
|
|
41
42
|
try {
|
|
42
|
-
const
|
|
43
|
-
const data = fs.readFileSync(configPath, 'utf-8');
|
|
43
|
+
const data = fs.readFileSync( configPath(), 'utf-8' );
|
|
44
44
|
return JSON.parse(data);
|
|
45
45
|
} catch (err) {
|
|
46
46
|
return {};
|
|
@@ -55,9 +55,8 @@ export function readConfigFile() {
|
|
|
55
55
|
export function saveConfig(data) {
|
|
56
56
|
write('Saving config file...');
|
|
57
57
|
try {
|
|
58
|
-
const savePath = path.join(process.cwd(), 'wp.advads')
|
|
59
58
|
const jsonData = JSON.stringify(data, null, 2);
|
|
60
|
-
fs.writeFileSync(
|
|
59
|
+
fs.writeFileSync( configPath(), jsonData );
|
|
61
60
|
settings = data;
|
|
62
61
|
} catch (err) {
|
|
63
62
|
write('Error writing config file:', err);
|
|
@@ -82,7 +81,7 @@ export function getSetting(key = 'all', defaultVal = '') {
|
|
|
82
81
|
return settings;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
return
|
|
84
|
+
return getPath( settings, key, defaultVal );
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
export function updateSetting(key, value) {
|
|
@@ -90,6 +89,27 @@ export function updateSetting(key, value) {
|
|
|
90
89
|
settings = readConfigFile();
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
settings =
|
|
92
|
+
settings = setPath(settings, key, value);
|
|
94
93
|
saveConfig(settings);
|
|
95
94
|
}
|
|
95
|
+
|
|
96
|
+
function getPath( object, key, defaultVal ) {
|
|
97
|
+
const value = String( key ).split( '.' ).reduce( ( cur, part ) => cur?.[ part ], object )
|
|
98
|
+
return value === undefined ? defaultVal : value
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function setPath( object, key, value ) {
|
|
102
|
+
const parts = String( key ).split( '.' )
|
|
103
|
+
let cur = object
|
|
104
|
+
|
|
105
|
+
for ( let i = 0; i < parts.length - 1; i++ ) {
|
|
106
|
+
const part = parts[ i ]
|
|
107
|
+
if ( cur[ part ] == null || typeof cur[ part ] !== 'object' ) {
|
|
108
|
+
cur[ part ] = {}
|
|
109
|
+
}
|
|
110
|
+
cur = cur[ part ]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
cur[ parts[ parts.length - 1 ] ] = value
|
|
114
|
+
return object
|
|
115
|
+
}
|