diff --git a/.github/actions/action.js b/.github/actions/action.js new file mode 100644 index 000000000..548e37d38 --- /dev/null +++ b/.github/actions/action.js @@ -0,0 +1,204 @@ +const core = require('@actions/core'); +const github = require('@actions/github'); +const {exec} = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const util = require('util'); +const execAsync = util.promisify(exec); +const SUBMODULE_PATH = 'meta/attributes/public'; +const TEMP_DIR = process.env.TEMP_DIR || 'temp_submodule'; +const PHP_FILES_DIR = process.env.PHP_FILES_DIR || 'filtered_submodule'; + +async function run() { + try { + const { token, gitUserName, gitUserEmail } = validateInputs(); + const octokit = github.getOctokit(token); + const context = github.context; + const tagName = await getTagName(context.ref); + const releaseName = `PhpStorm ${tagName.replace('v', '')}`; + + await configureGit(gitUserName, gitUserEmail); + + try { + await createTemporaryBranch(); + await manageSubmoduleFiles(TEMP_DIR, PHP_FILES_DIR); + } finally { + core.info('Cleaning up temporary directories...'); + await cleanupDirs([TEMP_DIR, PHP_FILES_DIR]); + } + + await commitAndPushChanges(tagName); + + await createGithubRelease(octokit, tagName, releaseName, context); + + } catch (error) { + core.error(`Run failed: ${error.message}`); + core.setFailed(error.message); + } +} + +// Top-level error handling +run().catch(error => { + core.error(`Unhandled error: ${error.message}`); + core.setFailed(error.message); +}); + +/** + * @param {string} dir - The directory to start reading from. + * @returns {Array} - A flat list of all file paths. + */ +async function readDirRecursively(dir) { + try { + const entries = await fs.promises.readdir(dir, { withFileTypes: true }); + const files = await Promise.all(entries.map(async (entry) => { + const fullPath = path.join(dir, entry.name); + return entry.isDirectory() ? await readDirRecursively(fullPath) : fullPath; + })); + return files.flat(); + } catch (error) { + core.error(`Error reading directory ${dir}: ${error.message}`); + throw error; + } +} + + +async function configureGit(gitUserName, gitUserEmail) { + core.info('Configuring Git...'); + try { + await safeExec(`git config --global user.name "${gitUserName}"`); + await safeExec(`git config --global user.email "${gitUserEmail}"`); + core.info(`Git configured successfully with user: ${gitUserName}, email: ${gitUserEmail}`); + } catch (error) { + core.error('Failed to configure Git.'); + core.setFailed(error.message); + throw error; + } +} + +async function manageSubmoduleFiles(tempDir, phpFilesDir) { + core.info('Initializing and updating submodule...'); + await safeExec('git submodule update --init --recursive'); + + core.info('Saving submodule files...'); + await createDir(tempDir) + await createDir(phpFilesDir); + await safeExec(`cp -r ${SUBMODULE_PATH}/* ${tempDir}`); + await copyPhpFiles(tempDir, phpFilesDir); + + core.info('Removing submodule...'); + await safeExec(`git submodule deinit -f -- ${SUBMODULE_PATH}`); + await safeExec(`git rm -f ${SUBMODULE_PATH}`); + await safeExec(`rm -rf .git/modules/${SUBMODULE_PATH}`); + + core.info('Restoring filtered PHP files...'); + await fs.promises.mkdir(`${SUBMODULE_PATH}`, { recursive: true }); + await safeExec(`cp -r ${phpFilesDir}/* ${SUBMODULE_PATH}`); +} + +async function copyPhpFiles(sourceDir, destinationDir) { + const phpFiles = []; + const allFiles = await readDirRecursively(sourceDir); + + await Promise.all( + allFiles.map(async (filePath) => { + if (filePath.endsWith('.php')) { + const fileName = path.basename(filePath); + const destPath = path.join(destinationDir, fileName); + phpFiles.push(filePath); + await fs.promises.copyFile(filePath, destPath); + } + }) + ); + + return phpFiles; +} + +async function createTemporaryBranch() { + const tempBranch = `release-${Date.now()}`; + core.info(`Creating temporary branch ${tempBranch}...`); + await safeExec(`git checkout -b ${tempBranch}`); +} + +async function commitAndPushChanges(tagName) { + core.info('Committing changes...'); + await safeExec('git add -f ' + SUBMODULE_PATH); + await safeExec('git commit -m "Convert submodule to regular files for release"'); + + core.info('Updating and pushing tag...'); + await safeExec(`git tag -f ${tagName}`); + await safeExec('git push origin --force --tags'); +} + +async function getTagName(ref) { + if (!ref.startsWith('refs/tags/')) { + core.error(`Invalid ref: ${ref}. This action should be triggered by a tag push.`); + throw new Error('This action expects a tag push event.'); + } + const tagName = ref.replace('refs/tags/', ''); + core.info(`Tag identified: ${tagName}`); + return tagName; +} + +async function createGithubRelease(octokit, tagName, releaseName, context) { + core.info(`Creating release ${releaseName} from tag ${tagName}...`); + const release = await octokit.rest.repos.createRelease({ + ...context.repo, + tag_name: tagName, + name: releaseName, + body: 'Automated release including submodule files', + draft: false, + prerelease: false + }); + + core.info('Release created successfully!'); + core.setOutput('release-url', release.data.html_url); +} + +async function cleanupDirs(directories) { + try { + await Promise.all( + directories.map(async (directory) => { + await fs.promises.rm(directory, { recursive: true, force: true }); + core.info(`Successfully cleaned: ${directory}`); + }) + ); + } catch (error) { + core.warning(`Error during cleanup: ${error.message}`); + } +} + +function validateInputs() { + const token = core.getInput('github-token', { required: true }); + const gitUserName = core.getInput('git-user-name') || 'GitHub Action'; + const gitUserEmail = core.getInput('git-user-email') || 'action@github.com'; + + if (!token) { + throw new Error('A valid GitHub Token is required to authenticate.'); + } + + return { token, gitUserName, gitUserEmail }; +} + +async function createDir(directory) { + try { + await fs.promises.mkdir(directory, { recursive: true }); + core.info(`Directory created: ${directory}`); + } catch (error) { + core.error(`Failed to create directory: ${directory}`); + throw error; + } +} + +async function safeExec(command) { + try { + const { stdout, stderr } = await execAsync(command); + if (stderr) { + core.warning(`Command warning: ${stderr}`); + } + return stdout.trim(); + } catch (error) { + core.error(`Command failed: ${command}`); + core.error(`Error: ${error.message}`); + throw error; + } +} diff --git a/.github/actions/action.yml b/.github/actions/action.yml new file mode 100644 index 000000000..e9b2fee36 --- /dev/null +++ b/.github/actions/action.yml @@ -0,0 +1,9 @@ +name: 'Create Release with Submodule Files' +description: 'Creates a GitHub release including files from a specified submodule' +inputs: + github-token: + description: 'GitHub token for authentication' + required: true +runs: + using: 'node16' + main: 'action.js' diff --git a/.github/actions/package-lock.json b/.github/actions/package-lock.json new file mode 100644 index 000000000..16a63cc4b --- /dev/null +++ b/.github/actions/package-lock.json @@ -0,0 +1,284 @@ +{ + "name": "phpstorm-stubs-actions", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "phpstorm-stubs-actions", + "version": "1.0.0", + "dependencies": { + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "license": "MIT", + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "license": "MIT", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/github": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", + "integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==", + "license": "MIT", + "dependencies": { + "@actions/http-client": "^2.2.0", + "@octokit/core": "^5.0.1", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-rest-endpoint-methods": "^10.0.0" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "license": "MIT" + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", + "integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", + "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", + "integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^23.0.1" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "license": "Apache-2.0" + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "license": "ISC" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/undici": { + "version": "5.28.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", + "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + } + } +} diff --git a/.github/actions/package.json b/.github/actions/package.json new file mode 100644 index 000000000..71c55e006 --- /dev/null +++ b/.github/actions/package.json @@ -0,0 +1,10 @@ +{ + "name": "phpstorm-stubs-actions", + "version": "1.0.0", + "description": "GitHub Actions for phpstorm-stubs", + "main": "action.js", + "dependencies": { + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0" + } +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea65e9150..4ab4731b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Build Docker Container run: docker compose -f docker-compose.yml build >/dev/null @@ -39,6 +41,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + submodules: recursive - name: Composer Install run: docker compose -f docker-compose.yml run test_runner composer install --no-progress diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..6c356e071 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: Create Release + +on: + push: + tags: + - 'v*' # This will match tags like v2024.3, etc. + +jobs: + create-release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + submodules: true + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '16' + + - name: Install Dependencies + run: cd .github/actions && npm install + + - name: Create Release + uses: ./.github/actions + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..54d0ea985 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "phpstorm-attributes"] + path = meta/attributes/public + url = git@github.com:JetBrains/phpstorm-attributes.git + branch = master diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index feaa0c923..b35fd7186 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -7,6 +7,7 @@ $finder = PhpCsFixer\Finder::create() ->in(__DIR__) + ->exclude('meta/attributes/public') ->append(['.php-cs-fixer.php']) ->notName('PhpStormStubsMap.php'); diff --git a/meta/attributes/ArrayShape.php b/meta/attributes/ArrayShape.php deleted file mode 100644 index 17a91ad5b..000000000 --- a/meta/attributes/ArrayShape.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * Example:
- * #[ArrayShape(["f" => "int", "string", "x" => "float"])] - * This usage applied on an element effectively means that the array has 3 dimensions, the keys are "f", 1, and "x", and the corresponding types are "int", "string", and "float". - */ -#[Attribute(Attribute::TARGET_FUNCTION|Attribute::TARGET_METHOD|Attribute::TARGET_PARAMETER|Attribute::TARGET_PROPERTY)] -class ArrayShape -{ - public function __construct(array $shape) {} -} diff --git a/meta/attributes/Deprecated.php b/meta/attributes/Deprecated.php deleted file mode 100644 index 5a54e5dc9..000000000 --- a/meta/attributes/Deprecated.php +++ /dev/null @@ -1,49 +0,0 @@ - - *
  • %parametersList%: parameters of the function call. For example, for the "f(1,2)" call, %parametersList% will be "1,2"
  • - *
  • %parameter0%,%parameter1%,%parameter2%,...: parameters of the function call. For example, for the "f(1,2)" call, %parameter1% will be "2"
  • - *
  • %name%: For "\x\f(1,2)", %name% will be "\x\f", for "$this->ff()", %name% will be "ff"
  • - *
  • %class%: If the attribute is provided for method "m", then for "$this->f()->m()", %class% will be "$this->f()"
  • - * - * The following example shows how to wrap a function call in another call and swap arguments:
    - * "#[Deprecated(replaceWith: "wrappedCall(%name%(%parameter1%, %parameter0%))")] f($a, $b){}
    - * f(1,2) will be replaced with wrappedCall(f(2,1)) - * @param string $since Element is deprecated starting with the provided PHP language level, applicable only for PhpStorm stubs entries - */ - public function __construct( - $reason = "", - $replacement = "", - #[ExpectedValues(self::PHP_VERSIONS)] $since = "5.6" - ) {} -} diff --git a/meta/attributes/ExpectedValues.php b/meta/attributes/ExpectedValues.php deleted file mode 100644 index 907170307..000000000 --- a/meta/attributes/ExpectedValues.php +++ /dev/null @@ -1,42 +0,0 @@ - - *
  • Code completion - expected arguments are displayed on the top of the suggestions list when used in comparison expressions
  • - *
  • Inspections [when used in a comparison with a value/assignment to/return from method] - the element absent from the expected values list produces the inspection warning
  • - *
  • Code generation - for example, when generating the 'switch' statement, all possible expected values are inserted automatically
  • - * - * - * Expected values can be any of the following: - * - * - * Expected arguments can be specified in any of the following ways: - * - * - * The attribute with the number of provided constructor arguments different from 1 will result in undefined behavior. - * @since 8.0 - */ -#[Attribute(Attribute::TARGET_FUNCTION|Attribute::TARGET_METHOD|Attribute::TARGET_PARAMETER|Attribute::TARGET_PROPERTY)] -class ExpectedValues -{ - public function __construct(array $values = [], array $flags = [], ?string $valuesFromClass = null, ?string $flagsFromClass = null) {} -} diff --git a/meta/attributes/Immutable.php b/meta/attributes/Immutable.php deleted file mode 100644 index 49b537e7e..000000000 --- a/meta/attributes/Immutable.php +++ /dev/null @@ -1,27 +0,0 @@ - - *
  • {@link Immutable::CONSTRUCTOR_WRITE_SCOPE}: write is allowed only in containing class constructor (default choice)
  • - *
  • {@link Immutable::PRIVATE_WRITE_SCOPE}: write is allowed only in places where the property would be accessible if it had 'private' visibility modifier
  • - *
  • {@link Immutable::PROTECTED_WRITE_SCOPE}: write is allowed only in places where the property would be accessible if it had 'protected' visibility modifier
  • - * - * @since 8.0 - */ -#[Attribute(Attribute::TARGET_PROPERTY|Attribute::TARGET_CLASS)] -class Immutable -{ - public const CONSTRUCTOR_WRITE_SCOPE = "constructor"; - public const PRIVATE_WRITE_SCOPE = "private"; - public const PROTECTED_WRITE_SCOPE = "protected"; - - public function __construct(#[ExpectedValues(valuesFromClass: Immutable::class)] $allowedWriteScope = self::CONSTRUCTOR_WRITE_SCOPE) {} -} diff --git a/meta/attributes/Language.php b/meta/attributes/Language.php deleted file mode 100644 index f8efe67d9..000000000 --- a/meta/attributes/Language.php +++ /dev/null @@ -1,20 +0,0 @@ -#[ObjectShape(["age" => "int", "name" => "string"])] - * - * This usage applied on an element effectively means that the object has 2 fields, the names are "age" and "name", and the corresponding types are "int" and "string". - */ -#[Attribute(Attribute::TARGET_FUNCTION|Attribute::TARGET_METHOD|Attribute::TARGET_PARAMETER|Attribute::TARGET_PROPERTY)] -class ObjectShape -{ - public function __construct(array $shape) {} -} diff --git a/meta/attributes/Pure.php b/meta/attributes/Pure.php deleted file mode 100644 index c4e95b6c8..000000000 --- a/meta/attributes/Pure.php +++ /dev/null @@ -1,20 +0,0 @@ -