@windwalker-io/core 4.1.11 → 4.2.0

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.
Files changed (72) hide show
  1. package/LICENSE +19 -19
  2. package/bin/release.js +3 -3
  3. package/core/index.d.ts +1 -0
  4. package/core/index.html +13 -0
  5. package/core/lib/main.ts +9 -0
  6. package/core/package.json +26 -0
  7. package/core/public/vite.svg +1 -0
  8. package/core/src/main.ts +23 -0
  9. package/core/src/style.css +95 -0
  10. package/core/src/typescript.svg +1 -0
  11. package/core/src/vite-env.d.ts +1 -0
  12. package/package.json +67 -52
  13. package/{postcss.config.cjs → postcss.config.js} +1 -1
  14. package/src/app/app.ts +50 -0
  15. package/src/app/index.ts +3 -0
  16. package/src/app/macros/defineJsModules.ts +5 -0
  17. package/src/app/macros/index.ts +1 -0
  18. package/src/asset-bundler.mjs +114 -0
  19. package/src/asset-sync.mjs +4 -1
  20. package/src/debugger/Store.vue +1 -1
  21. package/src/debugger/debugger.js +3 -5
  22. package/src/debugger/types/global.d.js +2 -2
  23. package/src/index.mjs +11 -9
  24. package/src/legacy/4.0/js-sync.mjs +74 -74
  25. package/src/next/fusion/index.ts +2 -0
  26. package/src/next/fusion/plugins/assets.ts +29 -0
  27. package/src/next/fusion/plugins/index.ts +3 -0
  28. package/src/next/fusion/plugins/systemjs.ts +66 -0
  29. package/src/next/fusion/processors/cloneAssets.ts +81 -0
  30. package/src/next/fusion/processors/cssModulize.ts +105 -0
  31. package/src/next/fusion/processors/index.ts +4 -0
  32. package/src/next/fusion/processors/installVendors.ts +178 -0
  33. package/src/next/fusion/processors/jsModulize.ts +296 -0
  34. package/src/next/index.ts +2 -0
  35. package/src/next/utilities/asset-sync.ts +47 -0
  36. package/src/next/utilities/crypto.ts +11 -0
  37. package/src/next/utilities/fs.ts +61 -0
  38. package/src/next/utilities/index.ts +5 -0
  39. package/src/next/utilities/modules.ts +17 -0
  40. package/tailwind/console.tailwind.config.cjs +1 -1
  41. package/tailwind.config.js +10 -0
  42. package/vite.config.debugger.ts +94 -0
  43. package/vite.config.next.ts +75 -0
  44. package/.gulp.json +0 -7
  45. package/dist/debugger/100-a64696bac484f689dc7f.js +0 -2
  46. package/dist/debugger/100.js.map +0 -1
  47. package/dist/debugger/153-2f3366cb4e48e0749485.js +0 -2
  48. package/dist/debugger/153.js.map +0 -1
  49. package/dist/debugger/282-6f9f84a149fc7e52beb5.js +0 -2
  50. package/dist/debugger/282.js.map +0 -1
  51. package/dist/debugger/358-bdcf2ec8126fe2a9a049.js +0 -2
  52. package/dist/debugger/358.js.map +0 -1
  53. package/dist/debugger/416-ac63d360de6c26cab89a.js +0 -2
  54. package/dist/debugger/416.js.map +0 -1
  55. package/dist/debugger/489-e2b77a72f97d9e96f9c0.js +0 -2
  56. package/dist/debugger/489.js.map +0 -1
  57. package/dist/debugger/694-f1f22e67d91a57498639.js +0 -2
  58. package/dist/debugger/694.js.map +0 -1
  59. package/dist/debugger/941-c22b0704c67ca5058678.js +0 -2
  60. package/dist/debugger/941.js.map +0 -1
  61. package/dist/debugger/debugger.js +0 -3
  62. package/dist/debugger/debugger.js.LICENSE.txt +0 -13
  63. package/dist/debugger/main.js.map +0 -1
  64. package/dist/debugger/windwalker-logo-h-w.svg +0 -1
  65. package/dist/debugger-console.css +0 -2
  66. package/dist/debugger-console.css.map +0 -1
  67. package/dist/debugger-console.js +0 -2
  68. package/dist/debugger-console.js.map +0 -1
  69. package/dist/images/windwalker-logo-h-w.svg +0 -1
  70. package/fusionfile.mjs +0 -96
  71. package/src/debugger/webpack.config.js +0 -9
  72. package/tailwind.config.cjs +0 -30
@@ -1,74 +1,74 @@
1
- import { findModules } from '@windwalker-io/core/src/index.mjs';
2
- import { dest as toDest, src, ts } from '@windwalker-io/fusion';
3
- import { postStream, prepareStream } from '@windwalker-io/fusion/src/lifecycles.js';
4
- import { extractDest } from '@windwalker-io/fusion/src/utilities/utilities.js';
5
- import { existsSync } from 'fs';
6
- import rename from 'gulp-rename';
7
- import path from 'path';
8
-
9
- /**
10
- * @deprecated
11
- */
12
- export function jsSync(source = 'src/Module', dest, options = {}) {
13
- const tsOptions = options.ts || {};
14
-
15
- if (!tsOptions.tsconfig) {
16
- tsOptions.tsconfig = path.resolve('tsconfig.json');
17
-
18
- if (!existsSync(tsOptions.tsconfig)) {
19
- tsOptions.tsconfig = path.resolve('node_modules/@windwalker-io/unicorn/tsconfig.js.json');
20
- }
21
- }
22
-
23
- const sourceList = [];
24
-
25
- sourceList.push(...findModules('**/assets/*.{js,mjs}'));
26
- sourceList.push(source + '**/assets/*.{js,mjs}');
27
-
28
- let stream = prepareStream(src(sourceList));
29
-
30
- stream = stream.pipe(rename((path) => {
31
- path.dirname = path.dirname.replace(/assets$/, '').toLowerCase();
32
- }));
33
-
34
- const jsDest = extractDest(dest);
35
-
36
- //
37
- // // if (dest.merge) {
38
- // // stream = stream.pipe(rename(path.basename(dest.file)));
39
- // // }
40
- //
41
- stream = stream.pipe(toDest(jsDest.path).on('error', e => console.error(e)));
42
-
43
- return Promise.all([
44
- new Promise((resolve) => {
45
- postStream(stream).on('end', (event) => {
46
- const data = {
47
- event,
48
- src,
49
- dest: jsDest,
50
- stream
51
- };
52
-
53
- resolve(data);
54
- });
55
- }),
56
- // Legacy mode
57
- ts(
58
- [
59
- ...findModules('**/assets/*.ts'),
60
- 'node_modules/@windwalker-io/unicorn/src/types/*.d.ts',
61
- `${source}/**/*.ts`,
62
- ],
63
- dest,
64
- {
65
- rename: (path) => {
66
- path.dirname = path.dirname.replace(/assets$/, '').toLowerCase();
67
- },
68
- ...tsOptions
69
- }
70
- )
71
- ]).then((v) => {
72
- return v[0];
73
- });
74
- }
1
+ import { findModules } from '@windwalker-io/core/src/index.mjs';
2
+ import { dest as toDest, src, ts } from '@windwalker-io/fusion';
3
+ import { postStream, prepareStream } from '@windwalker-io/fusion/src/lifecycles.js';
4
+ import { extractDest } from '@windwalker-io/fusion/src/utilities/utilities.js';
5
+ import { existsSync } from 'fs';
6
+ import rename from 'gulp-rename';
7
+ import path from 'path';
8
+
9
+ /**
10
+ * @deprecated
11
+ */
12
+ export function jsSync(source = 'src/Module', dest, options = {}) {
13
+ const tsOptions = options.ts || {};
14
+
15
+ if (!tsOptions.tsconfig) {
16
+ tsOptions.tsconfig = path.resolve('tsconfig.json');
17
+
18
+ if (!existsSync(tsOptions.tsconfig)) {
19
+ tsOptions.tsconfig = path.resolve('node_modules/@windwalker-io/unicorn/tsconfig.js.json');
20
+ }
21
+ }
22
+
23
+ const sourceList = [];
24
+
25
+ sourceList.push(...findModules('**/assets/*.{js,mjs}'));
26
+ sourceList.push(source + '**/assets/*.{js,mjs}');
27
+
28
+ let stream = prepareStream(src(sourceList));
29
+
30
+ stream = stream.pipe(rename((path) => {
31
+ path.dirname = path.dirname.replace(/assets$/, '').toLowerCase();
32
+ }));
33
+
34
+ const jsDest = extractDest(dest);
35
+
36
+ //
37
+ // // if (dest.merge) {
38
+ // // stream = stream.pipe(rename(path.basename(dest.file)));
39
+ // // }
40
+ //
41
+ stream = stream.pipe(toDest(jsDest.path).on('error', e => console.error(e)));
42
+
43
+ return Promise.all([
44
+ new Promise((resolve) => {
45
+ postStream(stream).on('end', (event) => {
46
+ const data = {
47
+ event,
48
+ src,
49
+ dest: jsDest,
50
+ stream
51
+ };
52
+
53
+ resolve(data);
54
+ });
55
+ }),
56
+ // Legacy mode
57
+ ts(
58
+ [
59
+ ...findModules('**/assets/*.ts'),
60
+ 'node_modules/@windwalker-io/unicorn/src/types/*.d.ts',
61
+ `${source}/**/*.ts`,
62
+ ],
63
+ dest,
64
+ {
65
+ rename: (path) => {
66
+ path.dirname = path.dirname.replace(/assets$/, '').toLowerCase();
67
+ },
68
+ ...tsOptions
69
+ }
70
+ )
71
+ ]).then((v) => {
72
+ return v[0];
73
+ });
74
+ }
@@ -0,0 +1,2 @@
1
+ export * from './plugins';
2
+ export * from './processors';
@@ -0,0 +1,29 @@
1
+ import { type FusionPlugin } from '@windwalker-io/fusion-next';
2
+ import { getAvailableForReposition, handleCloneAssets, handleReposition } from '../processors/cloneAssets';
3
+
4
+ export interface WindwalkerAssetsOptions {
5
+ clone?: Record<string, string>;
6
+ reposition?: Record<string, string>;
7
+ }
8
+
9
+ export function globalAssets(options: WindwalkerAssetsOptions): FusionPlugin {
10
+ return {
11
+ name: 'core:global-assets',
12
+ buildConfig(builder) {
13
+ const clone = options.clone || {};
14
+ let reposition = options.reposition || {};
15
+
16
+ reposition = { ...reposition, ...getAvailableForReposition(clone) };
17
+
18
+ // Handle reposition
19
+ handleReposition(builder, reposition);
20
+
21
+ const clonePatterns = Object.keys(clone);
22
+
23
+ // Handle clone
24
+ if (clonePatterns.length > 0) {
25
+ handleCloneAssets(builder, clonePatterns);
26
+ }
27
+ }
28
+ };
29
+ }
@@ -0,0 +1,3 @@
1
+ export * from './assets';
2
+ export * from './systemjs';
3
+
@@ -0,0 +1,66 @@
1
+ import fs from 'fs-extra';
2
+ import { resolve } from 'node:path';
3
+ import type { OutputAsset, OutputChunk } from 'rollup';
4
+ import type { PluginOption } from 'vite';
5
+
6
+ export function injectSystemJS(systemPath?: string, filter?: (file: OutputAsset | OutputChunk) => any): PluginOption {
7
+ systemPath ??= resolve('node_modules/systemjs/dist/system.min.js');
8
+
9
+ return {
10
+ name: 'core:inject-systemjs',
11
+ async generateBundle(options, bundle) {
12
+ if (options.format !== 'system') {
13
+ return;
14
+ }
15
+
16
+ const systemjsCode = fs.readFileSync(
17
+ resolve(systemPath),
18
+ 'utf-8'
19
+ );
20
+
21
+ for (const file of Object.values(bundle)) {
22
+ if (filter && !filter(file)) {
23
+ continue;
24
+ }
25
+
26
+ if (file.type === 'chunk' && file.isEntry && file.fileName.endsWith('.js')) {
27
+ file.code = systemjsCode + '\n' + file.code;
28
+ }
29
+ }
30
+ }
31
+ };
32
+ }
33
+
34
+ export function systemCSSFix(): PluginOption {
35
+ return {
36
+ name: 'core:systemjs-css-fix',
37
+ async generateBundle(options, bundle) {
38
+ if (options.format !== 'system') {
39
+ return;
40
+ }
41
+
42
+ for (const [fileName, chunk] of Object.entries(bundle)) {
43
+ if (fileName.endsWith('.css') && 'code' in chunk) {
44
+ const regex = /__vite_style__\.textContent\s*=\s*"([\s\S]*?)";/;
45
+ let match = chunk.code.match(regex);
46
+
47
+ // For minified
48
+ if (!match) {
49
+ const regex = /\.textContent\s*=\s*`([\s\S]*?)`/;
50
+ match = chunk.code.match(regex);
51
+ }
52
+
53
+ if (match && match[1]) {
54
+ chunk.code = match[1]
55
+ .replace(/\\"/g, '"')
56
+ .replace(/\\n/g, '\n')
57
+ .replace(/\\t/g, '\t')
58
+ .replace(/\\\\/g, '\\')
59
+ .replace(/\/\*\$vite\$:\d+\*\/$/, '')
60
+ }
61
+ }
62
+ }
63
+ }
64
+ };
65
+ }
66
+
@@ -0,0 +1,81 @@
1
+ import { callback, type ConfigBuilder } from '@windwalker-io/fusion-next';
2
+ import isGlob from 'is-glob';
3
+ import micromatch from 'micromatch';
4
+ import { normalize } from 'node:path';
5
+ import { relative } from 'node:path';
6
+ import { containsMiddleGlob, removeLastGlob, uniqId } from '../../utilities';
7
+
8
+ export function cloneAssets(patterns: Record<string, string>) {
9
+ return callback((taskName, builder) => {
10
+ const reposition = getAvailableForReposition(patterns);
11
+
12
+ handleReposition(builder, reposition);
13
+
14
+ handleCloneAssets(builder, Object.keys(patterns));
15
+
16
+ return null;
17
+ });
18
+ }
19
+
20
+ export function getAvailableForReposition(patterns: Record<string, string>) {
21
+ const reposition: Record<string, string> = {};
22
+
23
+ for (const from in patterns) {
24
+ // If clone from contains middle glob: eg. `assets/**/files`, we cannot handle the naming
25
+ // Let the naming options to handle it.
26
+ if (!containsMiddleGlob(from)) {
27
+ reposition[from] = patterns[from];
28
+ }
29
+ }
30
+
31
+ return reposition;
32
+ }
33
+
34
+ export function handleCloneAssets(builder: ConfigBuilder, clonePatterns: string[]) {
35
+ // An module starts `hidden:` will be ignored by fusion
36
+ const id = uniqId('hidden:clone-asset-') + '.js';
37
+
38
+ const task = builder.addTask(id);
39
+
40
+ builder.resolveIdCallbacks.push((src) => {
41
+ if (src === id) {
42
+ return id;
43
+ }
44
+ });
45
+
46
+ builder.loadCallbacks.push((src) => {
47
+ if (src === id) {
48
+ const glob = clonePatterns
49
+ // Replace slash to unix style
50
+ .map(v => v.replace(/\\/g, '/'))
51
+ // Glob in virtual module should start with /
52
+ .map(v => v.startsWith('./') || !v.startsWith('/') ? `/${v}` : v)
53
+ // wrap with quotes
54
+ .map(v => `'${v}'`)
55
+ // join it to string.
56
+ .join(', ');
57
+
58
+ return `import.meta.glob(${glob});\n`;
59
+ }
60
+ });
61
+ }
62
+
63
+ export function handleReposition(builder: ConfigBuilder, reposition: Record<string, string>) {
64
+ builder.assetFileNamesCallbacks.push((assetInfo) => {
65
+ const fileName = assetInfo.originalFileName!;
66
+
67
+ for (const base in reposition) {
68
+ if (match(fileName, base)) {
69
+ return normalize(reposition[base] + relative(removeLastGlob(base), fileName)).replace(/\\/g, '/');
70
+ }
71
+ }
72
+ });
73
+ }
74
+
75
+ function match(str: string, pattern: string) {
76
+ if (isGlob(pattern)) {
77
+ return micromatch.isMatch(str, pattern);
78
+ }
79
+
80
+ return str.startsWith(pattern);
81
+ }
@@ -0,0 +1,105 @@
1
+ import { stripUrlQuery } from '@/next';
2
+ import { type ConfigBuilder, css, type ProcessorInterface, type ProcessorPreview } from '@windwalker-io/fusion-next';
3
+ import { WatchTask } from '@windwalker-io/fusion-next/src/types';
4
+ import fg from 'fast-glob';
5
+ import fs from 'fs-extra';
6
+ import { parse } from 'node-html-parser';
7
+ import { normalize, resolve } from 'node:path';
8
+
9
+ export function cssModulize(entry: string, dest: string) {
10
+ return new CssModulizeProcessor(css(entry, dest));
11
+ }
12
+
13
+ class CssModulizeProcessor implements ProcessorInterface {
14
+
15
+ constructor(
16
+ protected processor: ReturnType<typeof css>,
17
+ protected bladePatterns: string[] = [],
18
+ protected cssPatterns: string[] = []
19
+ ) {
20
+
21
+ }
22
+
23
+ parseBlades(...bladePatterns: (string[] | string)[]) {
24
+ this.bladePatterns = this.bladePatterns.concat(bladePatterns.flat());
25
+
26
+ return this;
27
+ }
28
+
29
+ mergeCss(...css: (string[] | string)[]) {
30
+ this.cssPatterns = this.cssPatterns.concat(css.flat());
31
+
32
+ return this;
33
+ }
34
+
35
+ config(taskName: string, builder: ConfigBuilder) {
36
+ const tasks = this.processor.config(taskName, builder);
37
+ const task = tasks[0];
38
+ const inputFile = resolve(task.input);
39
+
40
+ // get blade styles and add watches
41
+ const bladeFiles = fg.globSync(this.bladePatterns);
42
+
43
+ for (const file of bladeFiles) {
44
+ builder.watches.push({
45
+ file,
46
+ moduleFile: inputFile,
47
+ updateType: 'css-update',
48
+ } satisfies WatchTask);
49
+ }
50
+
51
+ builder.loadCallbacks.push((src, options) => {
52
+ const file = stripUrlQuery(src);
53
+
54
+ if (normalize(file) === inputFile) {
55
+ const patterns = fg.globSync(
56
+ this.cssPatterns.map((v) => resolve(v))
57
+ .map(v => v.replace(/\\/g, '/'))
58
+ );
59
+
60
+ const imports = patterns
61
+ .map((pattern) => `@import "${pattern}";`)
62
+ .concat(this.parseStylesFromBlades(bladeFiles))
63
+ .join('\n');
64
+
65
+ let main = fs.readFileSync(file, 'utf-8');
66
+
67
+ main += `\n\n${imports}\n`;
68
+
69
+ return main;
70
+ }
71
+ });
72
+
73
+ return undefined;
74
+ }
75
+
76
+ parseStylesFromBlades(files: string[]) {
77
+ return files.map((file) => {
78
+ const bladeText = fs.readFileSync(file, 'utf8');
79
+
80
+ const html = parse(bladeText);
81
+
82
+ return html.querySelectorAll('style[type][data-macro],script[type][data-macro]')
83
+ .filter(
84
+ (el) => ['text/scss', 'text/css'].includes(el.getAttribute('type') || '')
85
+ )
86
+ .map((el) => {
87
+ const scope = el.getAttribute('data-scope');
88
+
89
+ if (scope) {
90
+ return `${scope} {
91
+ ${el.innerHTML}
92
+ }`;
93
+ } else {
94
+ return el.innerHTML;
95
+ }
96
+ });
97
+ })
98
+ .filter((c) => c.length > 0)
99
+ .flat();
100
+ }
101
+
102
+ preview(): ProcessorPreview[] {
103
+ return [];
104
+ }
105
+ }
@@ -0,0 +1,4 @@
1
+ export { cssModulize } from './cssModulize';
2
+ export { jsModulize } from './jsModulize';
3
+ export { installVendors } from './installVendors';
4
+ export { cloneAssets } from './cloneAssets';
@@ -0,0 +1,178 @@
1
+ import { callbackAfterBuild, copyGlob, symlink } from '@windwalker-io/fusion-next';
2
+ import fs from 'fs-extra';
3
+ import path from 'node:path';
4
+ import { loadJson } from '../../utilities';
5
+
6
+ export function installVendors(
7
+ npmVendors: string[] = [],
8
+ to: string = 'www/assets/vendor',
9
+ ) {
10
+ return callbackAfterBuild(() => findAndInstall(npmVendors, to));
11
+ }
12
+
13
+ enum InstallAction {
14
+ LINK = 'Link',
15
+ COPY = 'Copy',
16
+ }
17
+
18
+ export async function findAndInstall(npmVendors: string[] = [], to = 'www/assets/vendor') {
19
+ const root = to;
20
+ let vendors = npmVendors;
21
+ const action = process.env.INSTALL_VENDOR === 'hard' ? InstallAction.COPY : InstallAction.LINK;
22
+
23
+ console.log("");
24
+
25
+ if (!fs.existsSync(root)) {
26
+ fs.mkdirSync(root);
27
+ }
28
+
29
+ const dirs = fs.readdirSync(root, { withFileTypes: true })
30
+ .filter(d => d.isDirectory())
31
+ .map(dir => path.join(root, dir.name));
32
+
33
+ dirs.unshift(root);
34
+
35
+ dirs.forEach((dir) => {
36
+ deleteExists(dir);
37
+ });
38
+
39
+ const composerJsons = getInstalledComposerVendors()
40
+ .map((cv) => `vendor/${cv}/composer.json`)
41
+ .map((file) => loadJson(file))
42
+ .filter((composerJson) => composerJson?.extra?.windwalker != null);
43
+
44
+ // Install npm vendors
45
+ vendors = findNpmVendors(composerJsons).concat(vendors);
46
+ vendors = [...new Set(vendors)];
47
+
48
+ for (const vendor of vendors) {
49
+ const source = `node_modules/${vendor}/`;
50
+ if (fs.existsSync(source)) {
51
+ console.log(`[${action} NPM] node_modules/${vendor}/ => ${root}/${vendor}/`);
52
+ doInstall(source, `${root}/${vendor}/`);
53
+ }
54
+ }
55
+
56
+ // Install composer packages assets
57
+ for (const composerJson of composerJsons) {
58
+ const vendorName = composerJson.name;
59
+
60
+ let assets = composerJson?.extra?.windwalker?.assets?.link;
61
+
62
+ if (!assets) {
63
+ continue;
64
+ }
65
+
66
+ if (!assets.endsWith('/')) {
67
+ assets += '/';
68
+ }
69
+
70
+ if (fs.existsSync(`vendor/${vendorName}/${assets}`)) {
71
+ console.log(`[${action} Composer] vendor/${vendorName}/${assets} => ${root}/${vendorName}/`);
72
+ doInstall(`vendor/${vendorName}/${assets}`, `${root}/${vendorName}/`);
73
+ }
74
+ }
75
+
76
+ // Install legacy packages assets
77
+ // legacyComposerVendors.forEach((vendorName) => {
78
+ // console.log(vendorName, fs.existsSync(`vendor/${vendorName}/assets`));
79
+ // if (fs.existsSync(`vendor/${vendorName}/assets`)) {
80
+ // console.log(`[${action} Composer] vendor/${vendorName}/assets/ => ${root}/${vendorName}/`);
81
+ // doInstall(`vendor/${vendorName}/assets/`, `${root}/${vendorName}/`);
82
+ // }
83
+ // });
84
+
85
+ // Install local saved vendors
86
+ const staticVendorDir = 'resources/assets/vendor/';
87
+
88
+ if (fs.existsSync(staticVendorDir)) {
89
+ const staticVendors = fs.readdirSync(staticVendorDir);
90
+
91
+ for (const staticVendor of staticVendors) {
92
+ if (staticVendor.startsWith('@')) {
93
+ const subVendors = fs.readdirSync(staticVendorDir + staticVendor);
94
+
95
+ for (const subVendor of subVendors) {
96
+ const subVendorName = staticVendor + '/' + subVendor;
97
+ const source = staticVendorDir + subVendorName + '/';
98
+
99
+ if (fs.existsSync(source)) {
100
+ console.log(`[${action} Local] resources/assets/vendor/${subVendorName}/ => ${root}/${subVendorName}/`);
101
+ doInstall(source, `${root}/${subVendorName}/`);
102
+ }
103
+ }
104
+ } else {
105
+ let source = staticVendorDir + staticVendor;
106
+
107
+ if (fs.existsSync(source)) {
108
+ console.log(`[${action} Local] resources/assets/vendor/${staticVendor}/ => ${root}/${staticVendor}/`);
109
+ doInstall(source, `${root}/${staticVendor}/`);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ async function doInstall(source: string, dest: string) {
117
+ if (process.env.INSTALL_VENDOR === 'hard') {
118
+ await copyGlob(source + '/**/*', dest);
119
+ } else {
120
+ await symlink(source, dest);
121
+ }
122
+ }
123
+
124
+ function findNpmVendors(composerJsons: any[] = []) {
125
+ const pkg = path.resolve(process.cwd(), 'package.json');
126
+ const pkgJson = loadJson(pkg);
127
+
128
+ let vendors = Object.keys(pkgJson.devDependencies || {})
129
+ .concat(Object.keys(pkgJson.dependencies || {}))
130
+ .map(id => `node_modules/${id}/package.json`)
131
+ .map((file) => loadJson(file))
132
+ .filter(pkgJson => pkgJson?.windwalker != null)
133
+ .map(pkgJson => pkgJson?.windwalker.vendors || [])
134
+ .flat();
135
+
136
+ const vendorsFromComposer = composerJsons
137
+ .map((composerJson) => {
138
+ return [
139
+ ...composerJson?.extra?.windwalker?.asset_vendors || [],
140
+ ...composerJson?.extra?.windwalker?.assets?.exposes || [],
141
+ ...Object.keys(composerJson?.extra?.windwalker?.assets?.vendors || {})
142
+ ];
143
+ })
144
+ .flat();
145
+
146
+ return [...new Set(vendors.concat(vendorsFromComposer))];
147
+ }
148
+
149
+ function getInstalledComposerVendors() {
150
+ const composerFile = path.resolve(process.cwd(), 'composer.json');
151
+ const composerJson = loadJson(composerFile);
152
+
153
+ return [
154
+ ...new Set(
155
+ Object.keys(composerJson['require'] || {})
156
+ .concat(Object.keys(composerJson['require-dev'] || {}))
157
+ )
158
+ ];
159
+ }
160
+
161
+ function deleteExists(dir: string) {
162
+ if (!fs.existsSync(dir)) {
163
+ return;
164
+ }
165
+
166
+ const subDirs = fs.readdirSync(dir, { withFileTypes: true });
167
+
168
+ for (const subDir of subDirs) {
169
+ if (subDir.isSymbolicLink() || subDir.isFile()) {
170
+ fs.unlinkSync(path.join(dir, subDir.name));
171
+ } else if (subDir.isDirectory()) {
172
+ deleteExists(path.join(dir, subDir.name));
173
+ }
174
+ }
175
+
176
+ fs.rmdirSync(dir);
177
+ }
178
+