@citolab/tspci 2.7.1 → 2.8.4
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/CHANGELOG.md +44 -0
- package/package.json +18 -8
- package/scripts/test-init-local.sh +105 -0
- package/scripts/test-init-matrix.sh +163 -0
- package/src/cli.js +78 -18
- package/src/rollup-plugin-copy-files.js +91 -0
- package/src/rollup-plugin-postcss-string.js +56 -0
- package/src/rollup.config.dev.js +2 -3
- package/src/rollup.config.js +4 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,50 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.8.4](/compare/v2.8.3...v2.8.4) (2026-02-25)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @citolab/tspci
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [2.8.3](/compare/v2.8.2...v2.8.3) (2026-02-25)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @citolab/tspci
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [2.8.2](/compare/v2.8.1...v2.8.2) (2026-02-24)
|
|
23
|
+
|
|
24
|
+
**Note:** Version bump only for package @citolab/tspci
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## [2.8.1](/compare/v2.8.0...v2.8.1) (2026-02-24)
|
|
31
|
+
|
|
32
|
+
**Note:** Version bump only for package @citolab/tspci
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# [2.8.0](/compare/v2.7.1...v2.8.0) (2026-02-24)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Features
|
|
42
|
+
|
|
43
|
+
* add local test initialization scripts and rollup plugins 582f4d8
|
|
44
|
+
* enhance CLI options handling and project path resolution f9b51c6
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
6
50
|
## [2.7.1](/compare/v2.7.0...v2.7.1) (2026-02-09)
|
|
7
51
|
|
|
8
52
|
**Note:** Version bump only for package @citolab/tspci
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citolab/tspci",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.4",
|
|
4
4
|
"description": "an opiniated typescript ims-pci builder with tao integration",
|
|
5
5
|
"author": "patrick <patrick.deklein@cito.nl>",
|
|
6
6
|
"repository": "@citolab/tspci",
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"help": "tspci --help",
|
|
12
|
-
"init": "tspci init --force --path=../../pcis"
|
|
12
|
+
"init": "tspci init --force --path=../../pcis",
|
|
13
|
+
"test:init:local": "bash ./scripts/test-init-local.sh",
|
|
14
|
+
"test:init:smoke": "bash ./scripts/test-init-local.sh",
|
|
15
|
+
"test:init:matrix": "bash ./scripts/test-init-matrix.sh"
|
|
13
16
|
},
|
|
14
17
|
"type": "module",
|
|
15
18
|
"types": "types/index.d.ts",
|
|
@@ -25,22 +28,29 @@
|
|
|
25
28
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
26
29
|
"@tailwindcss/nesting": "0.0.0-insiders.565cd3e",
|
|
27
30
|
"@tailwindcss/postcss": "^4.1.18",
|
|
28
|
-
"@types/node": "^25.1.0",
|
|
29
|
-
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
30
|
-
"@typescript-eslint/parser": "^8.54.0",
|
|
31
31
|
"autoprefixer": "10.4.23",
|
|
32
32
|
"chalk": "5.6.2",
|
|
33
33
|
"chokidar": "^5.0.0",
|
|
34
34
|
"clear": "0.1.0",
|
|
35
|
+
"deepmerge": "^4.3.1",
|
|
36
|
+
"fast-glob": "^3.3.3",
|
|
35
37
|
"figlet": "1.10.0",
|
|
36
38
|
"inquirer": "13.2.2",
|
|
37
39
|
"postcss": "^8.5.6",
|
|
38
40
|
"postcss-import": "^16.1.1",
|
|
41
|
+
"postcss-load-config": "^6.0.1",
|
|
39
42
|
"rollup": "^4.57.1",
|
|
40
|
-
"rollup-plugin-copy": "^3.5.0",
|
|
41
43
|
"rollup-plugin-livereload": "^2.0.5",
|
|
42
|
-
"rollup-plugin-postcss": "^4.0.2",
|
|
43
44
|
"tailwindcss": "^4.1.18"
|
|
44
45
|
},
|
|
45
|
-
"
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^25.1.0",
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
49
|
+
"@typescript-eslint/parser": "^8.54.0"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public",
|
|
53
|
+
"registry": "https://registry.npmjs.org/"
|
|
54
|
+
},
|
|
55
|
+
"gitHead": "2ad2236ae56f3927ef2d836c987b86a94ba5c070"
|
|
46
56
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PKG_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
TEST_ROOT="${PKG_DIR}/tmp/init-local-test"
|
|
7
|
+
NPM_CACHE_DIR="${PKG_DIR}/tmp/npm-cache"
|
|
8
|
+
|
|
9
|
+
PCI_NAME="${1:-LocalTsPci}"
|
|
10
|
+
PROJECT_TYPE="${2:-typescript}"
|
|
11
|
+
DESCRIPTION="${3:-Local init test generated by script}"
|
|
12
|
+
|
|
13
|
+
TARGET_DIR="${TEST_ROOT}/${PCI_NAME}"
|
|
14
|
+
rm -rf "${TARGET_DIR}"
|
|
15
|
+
mkdir -p "${NPM_CACHE_DIR}"
|
|
16
|
+
rm -rf "${PKG_DIR}/tmp/init-local-test" "${PKG_DIR}/tmp/init-matrix-test"
|
|
17
|
+
rm -f "${PKG_DIR}"/citolab-*.tgz
|
|
18
|
+
|
|
19
|
+
echo "Packing local @citolab/tspci package..."
|
|
20
|
+
PACK_TGZ="$(cd "${PKG_DIR}" && npm pack --silent --ignore-scripts --cache "${NPM_CACHE_DIR}" | tail -n 1)"
|
|
21
|
+
PACK_PATH="${PKG_DIR}/${PACK_TGZ}"
|
|
22
|
+
cleanup() {
|
|
23
|
+
rm -f "${PACK_PATH}" 2>/dev/null || true
|
|
24
|
+
}
|
|
25
|
+
trap cleanup EXIT
|
|
26
|
+
|
|
27
|
+
echo "Generating project in: ${TARGET_DIR}"
|
|
28
|
+
node "${PKG_DIR}/src/cli.js" init \
|
|
29
|
+
--no-install \
|
|
30
|
+
--force \
|
|
31
|
+
--path "${TEST_ROOT}" \
|
|
32
|
+
--name "${PCI_NAME}" \
|
|
33
|
+
--description "${DESCRIPTION}" \
|
|
34
|
+
--project-type "${PROJECT_TYPE}"
|
|
35
|
+
|
|
36
|
+
echo ""
|
|
37
|
+
echo "Pointing generated project to local @citolab/tspci package..."
|
|
38
|
+
node -e "
|
|
39
|
+
const fs = require('fs');
|
|
40
|
+
const path = require('path');
|
|
41
|
+
const pkgPath = process.argv[1];
|
|
42
|
+
const localDep = process.argv[2];
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
44
|
+
pkg.devDependencies = pkg.devDependencies || {};
|
|
45
|
+
pkg.devDependencies['@citolab/tspci'] = localDep;
|
|
46
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
47
|
+
" "${TARGET_DIR}/package.json" "file:${PACK_PATH}"
|
|
48
|
+
|
|
49
|
+
echo ""
|
|
50
|
+
echo "Generated files:"
|
|
51
|
+
find "${TARGET_DIR}" -maxdepth 3 -type f | sort
|
|
52
|
+
|
|
53
|
+
EXPECTED_FILE="${TARGET_DIR}/src/index.ts"
|
|
54
|
+
if [[ "${PROJECT_TYPE}" == "javascript" ]]; then
|
|
55
|
+
EXPECTED_FILE="${TARGET_DIR}/src/index.js"
|
|
56
|
+
fi
|
|
57
|
+
if [[ "${PROJECT_TYPE}" == "preact+tailwind" ]]; then
|
|
58
|
+
EXPECTED_FILE="${TARGET_DIR}/src/index.tsx"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if [[ ! -f "${EXPECTED_FILE}" ]]; then
|
|
62
|
+
echo ""
|
|
63
|
+
echo "ERROR: expected entry file not found: ${EXPECTED_FILE}" >&2
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Installing dependencies in generated project..."
|
|
69
|
+
(cd "${TARGET_DIR}" && npm install --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "Running production build smoke test..."
|
|
73
|
+
node -e "
|
|
74
|
+
const { spawnSync } = require('child_process');
|
|
75
|
+
const targetDir = process.argv[1];
|
|
76
|
+
const result = spawnSync('npm', ['run', 'prod'], {
|
|
77
|
+
cwd: targetDir,
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
timeout: 180000
|
|
80
|
+
});
|
|
81
|
+
if (result.error) {
|
|
82
|
+
console.error(result.error.message);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
process.exit(result.status ?? 1);
|
|
86
|
+
" "${TARGET_DIR}"
|
|
87
|
+
|
|
88
|
+
DIST_JS="${TARGET_DIR}/dist/index.js"
|
|
89
|
+
if [[ ! -f "${DIST_JS}" ]]; then
|
|
90
|
+
echo ""
|
|
91
|
+
echo "ERROR: expected build output not found: ${DIST_JS}" >&2
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
DIST_TYPES="${TARGET_DIR}/dist/index.d.ts"
|
|
96
|
+
if [[ ! -f "${DIST_TYPES}" ]]; then
|
|
97
|
+
echo ""
|
|
98
|
+
echo "ERROR: expected type output not found: ${DIST_TYPES}" >&2
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
echo ""
|
|
103
|
+
echo "OK: found expected entry file: ${EXPECTED_FILE}"
|
|
104
|
+
echo "OK: production build output exists: ${DIST_JS}"
|
|
105
|
+
echo "OK: production type output exists: ${DIST_TYPES}"
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
TSPCI_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
REPO_ROOT="$(cd "${TSPCI_DIR}/../.." && pwd)"
|
|
7
|
+
TEST_ROOT="${TSPCI_DIR}/tmp/init-matrix-test"
|
|
8
|
+
NPM_CACHE_DIR="${TSPCI_DIR}/tmp/npm-cache"
|
|
9
|
+
|
|
10
|
+
clean_dir_contents() {
|
|
11
|
+
local dir_path="$1"
|
|
12
|
+
mkdir -p "${dir_path}"
|
|
13
|
+
find "${dir_path}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
mkdir -p "${NPM_CACHE_DIR}"
|
|
17
|
+
clean_dir_contents "${TEST_ROOT}"
|
|
18
|
+
|
|
19
|
+
# On Windows (Git Bash), convert Unix-style paths to native Windows paths so
|
|
20
|
+
# npm can resolve file: references correctly. No-op on Linux/macOS.
|
|
21
|
+
npm_path() {
|
|
22
|
+
if command -v cygpath &>/dev/null; then
|
|
23
|
+
cygpath -m "$1"
|
|
24
|
+
else
|
|
25
|
+
echo "$1"
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
TARBALLS=()
|
|
30
|
+
cleanup() {
|
|
31
|
+
for file in "${TARBALLS[@]:-}"; do
|
|
32
|
+
rm -f "${file}" 2>/dev/null || true
|
|
33
|
+
done
|
|
34
|
+
}
|
|
35
|
+
trap cleanup EXIT
|
|
36
|
+
|
|
37
|
+
prepare_pkg_for_pack() {
|
|
38
|
+
local pkg_dir="$1"
|
|
39
|
+
clean_dir_contents "${pkg_dir}/tmp/init-local-test"
|
|
40
|
+
clean_dir_contents "${pkg_dir}/tmp/init-matrix-test"
|
|
41
|
+
rm -f "${pkg_dir}"/citolab-*.tgz
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pack_local_pkg() {
|
|
45
|
+
local pkg_dir="$1"
|
|
46
|
+
local pkg_name="$2"
|
|
47
|
+
local tgz
|
|
48
|
+
prepare_pkg_for_pack "${pkg_dir}"
|
|
49
|
+
echo " - packing ${pkg_name}" >&2
|
|
50
|
+
tgz="$(cd "${pkg_dir}" && npm pack --silent --ignore-scripts --cache "${NPM_CACHE_DIR}" | tail -n 1 | tr -d '\r')"
|
|
51
|
+
local full_path="${pkg_dir}/${tgz}"
|
|
52
|
+
TARBALLS+=("${full_path}")
|
|
53
|
+
echo "${full_path}"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
echo "Packing local packages..."
|
|
57
|
+
TSPCI_TGZ="$(pack_local_pkg "${TSPCI_DIR}" "@citolab/tspci")"
|
|
58
|
+
QBCI_TGZ="$(pack_local_pkg "${REPO_ROOT}/lib/tspci-qbci" "@citolab/tspci-qbci")"
|
|
59
|
+
QTI3_TGZ="$(pack_local_pkg "${REPO_ROOT}/lib/tspci-qti3" "@citolab/tspci-qti3")"
|
|
60
|
+
TAO_TGZ="$(pack_local_pkg "${REPO_ROOT}/lib/tspci-tao" "@citolab/tspci-tao")"
|
|
61
|
+
PREACT_STORE_TGZ="$(pack_local_pkg "${REPO_ROOT}/lib/preact-store" "@citolab/preact-store")"
|
|
62
|
+
|
|
63
|
+
create_project() {
|
|
64
|
+
local project_name="$1"
|
|
65
|
+
local project_type="$2"
|
|
66
|
+
local description="$3"
|
|
67
|
+
local project_dir="${TEST_ROOT}/${project_name}"
|
|
68
|
+
|
|
69
|
+
node "${TSPCI_DIR}/src/cli.js" init \
|
|
70
|
+
--no-install \
|
|
71
|
+
--force \
|
|
72
|
+
--path "${TEST_ROOT}" \
|
|
73
|
+
--name "${project_name}" \
|
|
74
|
+
--description "${description}" \
|
|
75
|
+
--project-type "${project_type}"
|
|
76
|
+
|
|
77
|
+
node -e '
|
|
78
|
+
const fs = require("fs");
|
|
79
|
+
const pkgPath = process.argv[1];
|
|
80
|
+
const tspciTar = process.argv[2];
|
|
81
|
+
const preactStoreTar = process.argv[3];
|
|
82
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
83
|
+
pkg.devDependencies = pkg.devDependencies || {};
|
|
84
|
+
pkg.devDependencies["@citolab/tspci"] = `file:${tspciTar}`;
|
|
85
|
+
if (pkg.dependencies && pkg.dependencies["@citolab/preact-store"]) {
|
|
86
|
+
pkg.dependencies["@citolab/preact-store"] = `file:${preactStoreTar}`;
|
|
87
|
+
}
|
|
88
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
89
|
+
' "${project_dir}/package.json" "$(npm_path "${TSPCI_TGZ}")" "$(npm_path "${PREACT_STORE_TGZ}")"
|
|
90
|
+
|
|
91
|
+
(cd "${project_dir}" && npm install --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
assert_file() {
|
|
95
|
+
local file_path="$1"
|
|
96
|
+
if [[ ! -f "${file_path}" ]]; then
|
|
97
|
+
echo "ERROR: expected file not found: ${file_path}" >&2
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
run_base_build() {
|
|
103
|
+
local project_dir="$1"
|
|
104
|
+
(cd "${project_dir}" && npm run prod)
|
|
105
|
+
assert_file "${project_dir}/dist/index.js"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
echo "Scenario 1: vanilla PCI creates and builds"
|
|
109
|
+
create_project "VanillaPci" "javascript" "Vanilla PCI matrix test"
|
|
110
|
+
assert_file "${TEST_ROOT}/VanillaPci/src/index.js"
|
|
111
|
+
run_base_build "${TEST_ROOT}/VanillaPci"
|
|
112
|
+
|
|
113
|
+
echo "Scenario 2: TypeScript PCI (without tailwind/preact) creates and builds"
|
|
114
|
+
create_project "TypeScriptPci" "typescript" "TypeScript PCI matrix test"
|
|
115
|
+
assert_file "${TEST_ROOT}/TypeScriptPci/src/index.ts"
|
|
116
|
+
run_base_build "${TEST_ROOT}/TypeScriptPci"
|
|
117
|
+
|
|
118
|
+
echo "Scenario 3: TypeScript + tailwind PCI creates and builds"
|
|
119
|
+
create_project "TypeScriptTailwindPci" "preact+tailwind" "TypeScript + tailwind PCI matrix test"
|
|
120
|
+
assert_file "${TEST_ROOT}/TypeScriptTailwindPci/src/index.tsx"
|
|
121
|
+
run_base_build "${TEST_ROOT}/TypeScriptTailwindPci"
|
|
122
|
+
|
|
123
|
+
echo "Scenario 4: add tspci-qbci and export .ci package"
|
|
124
|
+
create_project "QbciPci" "typescript" "QBCI export matrix test"
|
|
125
|
+
(cd "${TEST_ROOT}/QbciPci" && npm install --save-dev "file:$(npm_path "${QBCI_TGZ}")" --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
126
|
+
(cd "${TEST_ROOT}/QbciPci" && npm run tspci -- add --target qbci)
|
|
127
|
+
(cd "${TEST_ROOT}/QbciPci" && npm run prod -- --target qbci)
|
|
128
|
+
ls "${TEST_ROOT}/QbciPci/ci-dist/"*.ci >/dev/null
|
|
129
|
+
|
|
130
|
+
echo "Scenario 5: add tspci-qti3 and export qti3 zip"
|
|
131
|
+
create_project "Qti3Pci" "typescript" "QTI3 export matrix test"
|
|
132
|
+
(cd "${TEST_ROOT}/Qti3Pci" && npm install --save-dev "file:$(npm_path "${QTI3_TGZ}")" --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
133
|
+
(cd "${TEST_ROOT}/Qti3Pci" && npm run tspci -- add --target qti3)
|
|
134
|
+
(cd "${TEST_ROOT}/Qti3Pci" && npm run prod -- --target qti3)
|
|
135
|
+
ls "${TEST_ROOT}/Qti3Pci/qti3-dist/"*.zip >/dev/null
|
|
136
|
+
|
|
137
|
+
echo "Scenario 6: add tspci-tao and export tao zip"
|
|
138
|
+
create_project "TaoPci" "typescript" "TAO export matrix test"
|
|
139
|
+
(cd "${TEST_ROOT}/TaoPci" && npm install --save-dev "file:$(npm_path "${TAO_TGZ}")" --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
140
|
+
(cd "${TEST_ROOT}/TaoPci" && npm run tspci -- add --target tao --ci)
|
|
141
|
+
node -e '
|
|
142
|
+
const fs = require("fs");
|
|
143
|
+
const pkgPath = process.argv[1];
|
|
144
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
145
|
+
pkg.config = pkg.config || {};
|
|
146
|
+
pkg.config.tspci = pkg.config.tspci || {};
|
|
147
|
+
if (!pkg.config.tspci.label) pkg.config.tspci.label = pkg.config.tspci.typeIdentifier || "tao";
|
|
148
|
+
if (!pkg.config.tspci.short) pkg.config.tspci.short = String(pkg.config.tspci.label).slice(0, 5);
|
|
149
|
+
if (!Array.isArray(pkg.config.tspci.score) || pkg.config.tspci.score.length === 0) {
|
|
150
|
+
pkg.config.tspci.score = ["MATCH_CORRECT", "NONE"];
|
|
151
|
+
}
|
|
152
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
153
|
+
' "${TEST_ROOT}/TaoPci/package.json"
|
|
154
|
+
(cd "${TEST_ROOT}/TaoPci" && npm run prod -- --target tao)
|
|
155
|
+
ls "${TEST_ROOT}/TaoPci/dist/tao-pci-"*.zip >/dev/null
|
|
156
|
+
|
|
157
|
+
echo "Scenario 7: preact-store with TypeScript + tailwind builds"
|
|
158
|
+
create_project "TailwindPreactStorePci" "preact+tailwind" "Tailwind + preact-store matrix test"
|
|
159
|
+
(cd "${TEST_ROOT}/TailwindPreactStorePci" && npm install --save "file:$(npm_path "${PREACT_STORE_TGZ}")" --cache "${NPM_CACHE_DIR}" --workspaces=false)
|
|
160
|
+
run_base_build "${TEST_ROOT}/TailwindPreactStorePci"
|
|
161
|
+
|
|
162
|
+
echo ""
|
|
163
|
+
echo "All matrix scenarios passed."
|
package/src/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ import inquirer from "inquirer";
|
|
|
14
14
|
const args = process.argv.slice(2);
|
|
15
15
|
|
|
16
16
|
// PK: retreive dirname, most of the time automaticly inserted in es modules
|
|
17
|
-
import { fileURLToPath } from "url";
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
18
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
19
|
const __dirname = path.dirname(__filename);
|
|
20
20
|
|
|
@@ -115,8 +115,9 @@ function selectOptions(prompt, options) {
|
|
|
115
115
|
{
|
|
116
116
|
type: "list",
|
|
117
117
|
message: prompt,
|
|
118
|
-
name: "
|
|
119
|
-
choices: options
|
|
118
|
+
name: "value",
|
|
119
|
+
choices: options,
|
|
120
|
+
default: options[0],
|
|
120
121
|
},
|
|
121
122
|
]);
|
|
122
123
|
}
|
|
@@ -134,6 +135,32 @@ function askOption(prompt) {
|
|
|
134
135
|
});
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
function getArgValue(longName, shortName = null) {
|
|
139
|
+
const longEq = args.find((arg) => arg.startsWith(`${longName}=`));
|
|
140
|
+
if (longEq) {
|
|
141
|
+
return longEq.slice(longName.length + 1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const shortEq = shortName ? args.find((arg) => arg.startsWith(`${shortName}=`)) : null;
|
|
145
|
+
if (shortEq) {
|
|
146
|
+
return shortEq.slice(shortName.length + 1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const longIndex = args.findIndex((arg) => arg === longName);
|
|
150
|
+
if (longIndex !== -1 && args[longIndex + 1]) {
|
|
151
|
+
return args[longIndex + 1];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (shortName) {
|
|
155
|
+
const shortIndex = args.findIndex((arg) => arg === shortName);
|
|
156
|
+
if (shortIndex !== -1 && args[shortIndex + 1]) {
|
|
157
|
+
return args[shortIndex + 1];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
137
164
|
function createDirectoryIfNotExists(file) {
|
|
138
165
|
const dir = path.dirname(file);
|
|
139
166
|
if (!fs.existsSync(dir)) {
|
|
@@ -216,14 +243,17 @@ const run = async () => {
|
|
|
216
243
|
|
|
217
244
|
// prompt for name
|
|
218
245
|
let pciName =
|
|
246
|
+
getArgValue("--name", "-n") ||
|
|
219
247
|
(await askOption(
|
|
220
248
|
"What your pci identifier (typeIdentifier). this can only contain alphanumeric characters (default: myPci) "
|
|
221
|
-
)) ||
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
249
|
+
)) ||
|
|
250
|
+
"myPci";
|
|
251
|
+
let basePath = process.cwd();
|
|
252
|
+
const pathArg = getArgValue("--path", "-p");
|
|
253
|
+
if (pathArg) {
|
|
254
|
+
basePath = pathArg;
|
|
226
255
|
}
|
|
256
|
+
let destinationFolder = path.resolve(process.cwd(), basePath, pciName);
|
|
227
257
|
// if args contains --force then delete the directory if already exists
|
|
228
258
|
if (args.indexOf("--force") >= 0 || args.indexOf("-f") >= 0) {
|
|
229
259
|
if (fs.existsSync(destinationFolder)) {
|
|
@@ -249,16 +279,27 @@ const run = async () => {
|
|
|
249
279
|
}
|
|
250
280
|
console.log(chalk.green(`pci: ${pciName}`));
|
|
251
281
|
const description =
|
|
282
|
+
getArgValue("--description", "-dsc") ||
|
|
252
283
|
(await askOption("What is the description of your pci? (default: pci created with tspci)")) ||
|
|
253
284
|
"pci created with tspci";
|
|
254
285
|
|
|
255
|
-
const
|
|
256
|
-
|
|
286
|
+
const projectTypes = ["preact+tailwind", "typescript", "javascript"];
|
|
287
|
+
const projectTypeArg = getArgValue("--project-type", "-pt");
|
|
288
|
+
const selectedProjectType = projectTypeArg
|
|
289
|
+
? projectTypes.find((projectType) => projectType === projectTypeArg)
|
|
290
|
+
: null;
|
|
291
|
+
if (projectTypeArg && !selectedProjectType) {
|
|
292
|
+
console.log(chalk.red(`Unknown project type "${projectTypeArg}". Use one of: ${projectTypes.join(", ")}`));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const options = selectedProjectType ? { value: selectedProjectType } : await selectOptions("Type of project?", projectTypes);
|
|
296
|
+
const projectType = options?.value || "typescript";
|
|
297
|
+
console.log(chalk.green(`Option: ${projectType}`));
|
|
257
298
|
// get relative path to executable
|
|
258
299
|
const cliPath = __dirname;
|
|
259
300
|
|
|
260
301
|
// create the project folder
|
|
261
|
-
fs.mkdirSync(destinationFolder);
|
|
302
|
+
fs.mkdirSync(destinationFolder, { recursive: true });
|
|
262
303
|
|
|
263
304
|
// copy the content of preset folder to the current folder
|
|
264
305
|
const presetFolder = path.resolve(cliPath, "./../preset/base");
|
|
@@ -284,7 +325,7 @@ const run = async () => {
|
|
|
284
325
|
}
|
|
285
326
|
packageJsonContentJson.config.tspci.typeIdentifier = pciName;
|
|
286
327
|
|
|
287
|
-
if (
|
|
328
|
+
if (projectType === "preact+tailwind") {
|
|
288
329
|
console.log(chalk.green("Adding tailwind css"));
|
|
289
330
|
|
|
290
331
|
// read postcss.config.js
|
|
@@ -327,7 +368,7 @@ const run = async () => {
|
|
|
327
368
|
copyDir(path.resolve(cliPath, "./../preset/tailwind"), destinationFolder);
|
|
328
369
|
}
|
|
329
370
|
|
|
330
|
-
if (
|
|
371
|
+
if (projectType === "preact+tailwind") {
|
|
331
372
|
console.log(chalk.green("Adding preact"));
|
|
332
373
|
// delete index.ts
|
|
333
374
|
// fs.rmSync(path.join(destinationFolder, "src/index.ts"), { force: true });
|
|
@@ -344,7 +385,7 @@ const run = async () => {
|
|
|
344
385
|
fs.writeFileSync(packageJson, newPackageJsonContent);
|
|
345
386
|
}
|
|
346
387
|
|
|
347
|
-
if (
|
|
388
|
+
if (projectType === "typescript") {
|
|
348
389
|
copyDirAndReplaceInFiles(
|
|
349
390
|
path.resolve(cliPath, "./../preset/typescript/src"),
|
|
350
391
|
path.join(destinationFolder, "src"),
|
|
@@ -356,7 +397,7 @@ const run = async () => {
|
|
|
356
397
|
fs.writeFileSync(packageJson, newPackageJsonContent);
|
|
357
398
|
}
|
|
358
399
|
|
|
359
|
-
if (
|
|
400
|
+
if (projectType === "javascript") {
|
|
360
401
|
copyDirAndReplaceInFiles(
|
|
361
402
|
path.resolve(cliPath, "./../preset/javascript/src"),
|
|
362
403
|
path.join(destinationFolder, "src"),
|
|
@@ -384,6 +425,7 @@ const run = async () => {
|
|
|
384
425
|
return;
|
|
385
426
|
} else {
|
|
386
427
|
console.log(chalk.yellow("Skipping npm install, run npm install in the project folder to install dependencies"));
|
|
428
|
+
return;
|
|
387
429
|
}
|
|
388
430
|
}
|
|
389
431
|
|
|
@@ -394,7 +436,9 @@ const run = async () => {
|
|
|
394
436
|
return;
|
|
395
437
|
}
|
|
396
438
|
const version = args.indexOf("--next") !== -1 ? "next" : "latest";
|
|
397
|
-
const
|
|
439
|
+
const passCiFlag = args.indexOf("--ci") !== -1;
|
|
440
|
+
const packageFilePath = path.join(PACKAGE_ROOT_PATH, "package.json");
|
|
441
|
+
const packageFileContent = fs.readFileSync(packageFilePath, "utf8");
|
|
398
442
|
const packageJson = JSON.parse(packageFileContent);
|
|
399
443
|
|
|
400
444
|
const modifyPci = () => {
|
|
@@ -402,10 +446,13 @@ const run = async () => {
|
|
|
402
446
|
let init = false;
|
|
403
447
|
if (fs.existsSync(scriptFile)) {
|
|
404
448
|
// run init() script
|
|
405
|
-
import(
|
|
449
|
+
import(pathToFileURL(scriptFile).href).then((script) => {
|
|
406
450
|
if (script.init) {
|
|
407
451
|
init = true;
|
|
408
452
|
console.log(chalk.green(`Running init script for ${targetName}`));
|
|
453
|
+
if (passCiFlag) {
|
|
454
|
+
process.argv.push("--ci");
|
|
455
|
+
}
|
|
409
456
|
script.init();
|
|
410
457
|
} else {
|
|
411
458
|
if (!init) {
|
|
@@ -423,6 +470,19 @@ const run = async () => {
|
|
|
423
470
|
stdio: [0, 1, 2],
|
|
424
471
|
});
|
|
425
472
|
}
|
|
473
|
+
|
|
474
|
+
// add a package script so users can export with a single command
|
|
475
|
+
const targetArg = args[targetIndex + 1];
|
|
476
|
+
if (targetArg) {
|
|
477
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
478
|
+
const packageScriptName = `package:${targetArg}`;
|
|
479
|
+
if (!packageJson.scripts[packageScriptName]) {
|
|
480
|
+
packageJson.scripts[packageScriptName] = `tspci --target ${targetArg}`;
|
|
481
|
+
fs.writeFileSync(packageFilePath, JSON.stringify(packageJson, null, 2), "utf8");
|
|
482
|
+
console.log(chalk.green(`Added script "${packageScriptName}" to package.json`));
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
426
486
|
modifyPci();
|
|
427
487
|
|
|
428
488
|
return;
|
|
@@ -451,7 +511,7 @@ const run = async () => {
|
|
|
451
511
|
return;
|
|
452
512
|
}
|
|
453
513
|
const scriptFile = path.join(path.join(path.join(NODE_MODULES, `${targetName}`), "src"), `createPackage.mjs`);
|
|
454
|
-
import(
|
|
514
|
+
import(pathToFileURL(scriptFile).href).then((script) => {
|
|
455
515
|
script.bundle();
|
|
456
516
|
});
|
|
457
517
|
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fg from "fast-glob";
|
|
4
|
+
|
|
5
|
+
function hasGlobSyntax(value) {
|
|
6
|
+
return /[*?[\]{}()!+@]/.test(value);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getGlobBase(pattern) {
|
|
10
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
11
|
+
const parts = normalized.split("/");
|
|
12
|
+
const baseParts = [];
|
|
13
|
+
for (const part of parts) {
|
|
14
|
+
if (hasGlobSyntax(part)) {
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
baseParts.push(part);
|
|
18
|
+
}
|
|
19
|
+
return baseParts.length > 0 ? baseParts.join("/") : ".";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function copyDirectoryRecursive(sourceDir, destinationDir) {
|
|
23
|
+
fs.mkdirSync(destinationDir, { recursive: true });
|
|
24
|
+
for (const item of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
25
|
+
const sourcePath = path.join(sourceDir, item.name);
|
|
26
|
+
const destinationPath = path.join(destinationDir, item.name);
|
|
27
|
+
if (item.isDirectory()) {
|
|
28
|
+
copyDirectoryRecursive(sourcePath, destinationPath);
|
|
29
|
+
} else if (item.isFile()) {
|
|
30
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
31
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function copyTarget(target, flatten) {
|
|
37
|
+
const srcPattern = target?.src;
|
|
38
|
+
const destination = target?.dest;
|
|
39
|
+
if (!srcPattern || !destination) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const matches = await fg(srcPattern, { dot: true, onlyFiles: false });
|
|
44
|
+
if (matches.length === 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const basePath = hasGlobSyntax(srcPattern) ? getGlobBase(srcPattern) : null;
|
|
49
|
+
|
|
50
|
+
for (const match of matches) {
|
|
51
|
+
const sourcePath = path.resolve(match);
|
|
52
|
+
const sourceStats = fs.statSync(sourcePath);
|
|
53
|
+
const basename = path.basename(sourcePath);
|
|
54
|
+
const sourceDirname = path.dirname(sourcePath);
|
|
55
|
+
|
|
56
|
+
let destinationFolder = destination;
|
|
57
|
+
if (!flatten && basePath) {
|
|
58
|
+
const relativeDir = path.relative(path.resolve(basePath), sourceDirname);
|
|
59
|
+
destinationFolder = relativeDir ? path.join(destination, relativeDir) : destination;
|
|
60
|
+
}
|
|
61
|
+
const destinationPath = path.join(destinationFolder, basename);
|
|
62
|
+
|
|
63
|
+
if (sourceStats.isDirectory()) {
|
|
64
|
+
copyDirectoryRecursive(sourcePath, destinationPath);
|
|
65
|
+
} else if (sourceStats.isFile()) {
|
|
66
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
67
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function copyFiles(options = {}) {
|
|
73
|
+
const targets = Array.isArray(options.targets) ? options.targets : [];
|
|
74
|
+
const flatten = options.flatten !== false;
|
|
75
|
+
|
|
76
|
+
const copyAllTargets = async () => {
|
|
77
|
+
for (const target of targets) {
|
|
78
|
+
await copyTarget(target, flatten);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
name: "copy-files",
|
|
84
|
+
async buildStart() {
|
|
85
|
+
await copyAllTargets();
|
|
86
|
+
},
|
|
87
|
+
async writeBundle() {
|
|
88
|
+
await copyAllTargets();
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import postcss from "postcss";
|
|
2
|
+
import loadPostCssConfig from "postcss-load-config";
|
|
3
|
+
|
|
4
|
+
export function postcssString(options = {}) {
|
|
5
|
+
const extensions = options.extensions || [".css"];
|
|
6
|
+
const configEnabled = options.config !== false;
|
|
7
|
+
const configCache = new Map();
|
|
8
|
+
|
|
9
|
+
const loadConfig = async (cwd) => {
|
|
10
|
+
if (configCache.has(cwd)) {
|
|
11
|
+
return configCache.get(cwd);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let loaded = { plugins: [], options: {} };
|
|
15
|
+
if (configEnabled) {
|
|
16
|
+
try {
|
|
17
|
+
const result = await loadPostCssConfig({}, cwd);
|
|
18
|
+
loaded = {
|
|
19
|
+
plugins: result?.plugins || [],
|
|
20
|
+
options: result?.options || {},
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (!String(error?.message || "").includes("No PostCSS Config found")) {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
configCache.set(cwd, loaded);
|
|
30
|
+
return loaded;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
name: "postcss-string",
|
|
35
|
+
async transform(code, id) {
|
|
36
|
+
const shouldProcess = extensions.some((ext) => id.endsWith(ext));
|
|
37
|
+
if (!shouldProcess) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const cwd = process.cwd();
|
|
42
|
+
const { plugins, options: configOptions } = await loadConfig(cwd);
|
|
43
|
+
const result = await postcss(plugins).process(code, {
|
|
44
|
+
...configOptions,
|
|
45
|
+
from: id,
|
|
46
|
+
to: id,
|
|
47
|
+
map: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
code: `export default ${JSON.stringify(result.css)};`,
|
|
52
|
+
map: { mappings: "" },
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
package/src/rollup.config.dev.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import copy from "rollup-plugin-copy";
|
|
2
1
|
import livereload from "rollup-plugin-livereload";
|
|
3
2
|
// PK: not the official npm package, but a copy, needed watch functionality
|
|
4
3
|
import { liveServer } from "./rollup-plugin-live-server.js";
|
|
4
|
+
import { copyFiles } from "./rollup-plugin-copy-files.js";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import rollupConfig from "./rollup.config.js"; // Make sure this exports an object with `output` and `plugins`
|
|
7
7
|
|
|
@@ -18,13 +18,12 @@ const livesrvr = liveServer({
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
// Configure copy plugin to watch for changes
|
|
21
|
-
const watchassets =
|
|
21
|
+
const watchassets = copyFiles({
|
|
22
22
|
targets: [
|
|
23
23
|
{ src: "./src/**/*.json", dest: "dist" },
|
|
24
24
|
{ src: "./src/**/*.svg", dest: "dist" },
|
|
25
25
|
{ src: "./src/**/*.png", dest: "dist" },
|
|
26
26
|
],
|
|
27
|
-
watch: true, // Enable watching for changes
|
|
28
27
|
});
|
|
29
28
|
|
|
30
29
|
// Modify the existing Rollup config
|
package/src/rollup.config.js
CHANGED
|
@@ -3,12 +3,10 @@ import typescript from "@rollup/plugin-typescript";
|
|
|
3
3
|
import alias from "@rollup/plugin-alias";
|
|
4
4
|
import image from "@rollup/plugin-image";
|
|
5
5
|
import replace from "@rollup/plugin-replace";
|
|
6
|
-
import postcss from "rollup-plugin-postcss";
|
|
7
6
|
import commonjs from "@rollup/plugin-commonjs"; // added this when added react-redux, gave an ' 'default' is not exported by node_modules/prop-types/index.js'
|
|
8
7
|
import json from "@rollup/plugin-json";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import copy from "rollup-plugin-copy"; // copying assets to the assets folder in dist ( not for PCI, those assets are bundled )
|
|
8
|
+
import { postcssString } from "./rollup-plugin-postcss-string.js";
|
|
9
|
+
import { copyFiles } from "./rollup-plugin-copy-files.js";
|
|
12
10
|
|
|
13
11
|
import fs from "fs";
|
|
14
12
|
import path from "path";
|
|
@@ -59,13 +57,10 @@ export default {
|
|
|
59
57
|
tsconfig: `${PACKAGE_ROOT_PATH}/tsconfig.json`,
|
|
60
58
|
declarationDir: `${PACKAGE_ROOT_PATH}/dist`
|
|
61
59
|
}),
|
|
62
|
-
|
|
63
|
-
extract: false, // not extracting embeds the js in the build, which is what we need for shipping it
|
|
64
|
-
modules: false, // tried modules at first, could work, but not with html in the qti file
|
|
65
|
-
inject: false, // does not inject the imported styles in the head
|
|
60
|
+
postcssString({
|
|
66
61
|
extensions: [".css"],
|
|
67
62
|
}),
|
|
68
|
-
|
|
63
|
+
copyFiles({
|
|
69
64
|
targets: [
|
|
70
65
|
{ src: "src/assets", dest: "dist" }, // copy asses to dist folder
|
|
71
66
|
],
|